From 8aed587f3e2c69988928363c0be5ce50b176f689 Mon Sep 17 00:00:00 2001 From: smtmfft <99081233+smtmfft@users.noreply.github.com> Date: Mon, 10 Apr 2023 18:04:24 +0800 Subject: [PATCH 001/102] fix a typo in comment (#1351) ### Description Fix a typo found by another community developer ### Issue Link N/A ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents N/A ### How Has This Been Tested? N/A --- .../src/evm_circuit/util/math_gadget/mul_add_words.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs index 4d3abd35fd..27792a9abc 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs @@ -24,7 +24,7 @@ use halo2_proofs::{ /// t2 = a0 * b2 + a2 * b0 + a1 * b1, contribute to above 128 bit /// t3 = a0 * b3 + a3 * b0 + a2 * b1 + a1 * b2, contribute to above 192 bit /// -/// so t0 ~ t1 include all contributions to the low 256-bit of product, with +/// so t0 ~ t3 include all contributions to the low 256-bit of product, with /// a maximum 68-bit radix (the part higher than 256-bit), denoted as carry_hi /// Similarly, we define carry_lo as the radix of contributions to the low /// 128-bit of the product. @@ -32,8 +32,8 @@ use halo2_proofs::{ /// allocate 9 bytes for them each /// /// Finally we just prove: -/// t0 + t1 * 2^64 = + carry_lo -/// t2 + t3 * 2^64 + carry_lo = + carry_hi +/// t0 + t1 * 2^64 = + carry_lo * 2^128 +/// t2 + t3 * 2^64 + carry_lo = + carry_hi * 2^128 /// /// Last, we sum the parts that are higher than 256-bit in the multiplication /// into overflow From 0e76d2b25e62c22f75b26a64d9d7ea78bb3fede0 Mon Sep 17 00:00:00 2001 From: Paul <108982045+ChengYueJia@users.noreply.github.com> Date: Mon, 10 Apr 2023 21:56:59 +0800 Subject: [PATCH 002/102] Gather all test-related into test mod. (#1300) ### Issue Link * First mentioned in #953 * Pr link This is the second pr for this. The older one #1003 is abandoned as there are too much conflicts. ### Contents * Gather test related into test mod. * Gather most of the `impl Circuit` into `dev.mod` This is for distinct the `test-circuits` and the test features. #1144 --- circuit-benchmarks/Cargo.toml | 2 +- circuit-benchmarks/src/bytecode_circuit.rs | 6 +- circuit-benchmarks/src/copy_circuit.rs | 6 +- circuit-benchmarks/src/evm_circuit.rs | 6 +- circuit-benchmarks/src/exp_circuit.rs | 6 +- circuit-benchmarks/src/packed_multi_keccak.rs | 6 +- integration-tests/Cargo.toml | 2 +- .../src/integration_test_circuits.rs | 28 +- zkevm-circuits/Cargo.toml | 2 +- zkevm-circuits/src/bytecode_circuit.rs | 9 +- .../src/bytecode_circuit/circuit.rs | 294 ----------- zkevm-circuits/src/bytecode_circuit/dev.rs | 86 ++-- zkevm-circuits/src/bytecode_circuit/test.rs | 283 +++++++++++ zkevm-circuits/src/copy_circuit.rs | 458 +----------------- zkevm-circuits/src/copy_circuit/dev.rs | 76 +++ zkevm-circuits/src/copy_circuit/test.rs | 345 +++++++++++++ zkevm-circuits/src/copy_circuit/util.rs | 22 + zkevm-circuits/src/evm_circuit.rs | 45 +- zkevm-circuits/src/evm_circuit/test.rs | 36 ++ zkevm-circuits/src/exp_circuit.rs | 219 +-------- zkevm-circuits/src/exp_circuit/dev.rs | 36 ++ zkevm-circuits/src/exp_circuit/param.rs | 10 + zkevm-circuits/src/exp_circuit/test.rs | 145 ++++++ zkevm-circuits/src/keccak_circuit.rs | 48 +- zkevm-circuits/src/keccak_circuit/dev.rs | 47 ++ zkevm-circuits/src/keccak_circuit/test.rs | 10 +- zkevm-circuits/src/pi_circuit.rs | 232 +-------- zkevm-circuits/src/pi_circuit/dev.rs | 84 ++++ zkevm-circuits/src/pi_circuit/param.rs | 5 + zkevm-circuits/src/pi_circuit/test.rs | 126 +++++ zkevm-circuits/src/root_circuit.rs | 92 +--- zkevm-circuits/src/root_circuit/test.rs | 82 ++++ zkevm-circuits/src/state_circuit.rs | 79 +-- .../src/state_circuit/constraint_builder.rs | 3 +- zkevm-circuits/src/state_circuit/dev.rs | 119 +++++ .../state_circuit/lexicographic_ordering.rs | 2 +- .../multiple_precision_integer.rs | 2 +- zkevm-circuits/src/state_circuit/param.rs | 3 + zkevm-circuits/src/state_circuit/test.rs | 67 +-- zkevm-circuits/src/super_circuit.rs | 193 +------- zkevm-circuits/src/super_circuit/test.rs | 183 +++++++ zkevm-circuits/src/table.rs | 4 +- zkevm-circuits/src/tx_circuit.rs | 181 +------ zkevm-circuits/src/tx_circuit/dev.rs | 61 +++ zkevm-circuits/src/tx_circuit/test.rs | 108 +++++ zkevm-circuits/src/witness/block.rs | 2 +- 46 files changed, 1953 insertions(+), 1908 deletions(-) create mode 100644 zkevm-circuits/src/bytecode_circuit/test.rs create mode 100644 zkevm-circuits/src/copy_circuit/dev.rs create mode 100644 zkevm-circuits/src/copy_circuit/test.rs create mode 100644 zkevm-circuits/src/copy_circuit/util.rs create mode 100644 zkevm-circuits/src/evm_circuit/test.rs create mode 100644 zkevm-circuits/src/exp_circuit/dev.rs create mode 100644 zkevm-circuits/src/exp_circuit/param.rs create mode 100644 zkevm-circuits/src/exp_circuit/test.rs create mode 100644 zkevm-circuits/src/keccak_circuit/dev.rs create mode 100644 zkevm-circuits/src/pi_circuit/dev.rs create mode 100644 zkevm-circuits/src/pi_circuit/param.rs create mode 100644 zkevm-circuits/src/pi_circuit/test.rs create mode 100644 zkevm-circuits/src/root_circuit/test.rs create mode 100644 zkevm-circuits/src/state_circuit/dev.rs create mode 100644 zkevm-circuits/src/state_circuit/param.rs create mode 100644 zkevm-circuits/src/super_circuit/test.rs create mode 100644 zkevm-circuits/src/tx_circuit/dev.rs create mode 100644 zkevm-circuits/src/tx_circuit/test.rs diff --git a/circuit-benchmarks/Cargo.toml b/circuit-benchmarks/Cargo.toml index 3646c329a5..222db7931d 100644 --- a/circuit-benchmarks/Cargo.toml +++ b/circuit-benchmarks/Cargo.toml @@ -11,7 +11,7 @@ halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.gi ark-std = { version = "0.3", features = ["print-trace"] } zkevm-circuits = { path = "../zkevm-circuits", features = ["test"]} keccak256 = { path = "../keccak256" } -bus-mapping = { path = "../bus-mapping" } +bus-mapping = { path = "../bus-mapping", features = ["test"] } rand_xorshift = "0.3" rand = "0.8" itertools = "0.10" diff --git a/circuit-benchmarks/src/bytecode_circuit.rs b/circuit-benchmarks/src/bytecode_circuit.rs index 0142ce3f9c..16c055410e 100644 --- a/circuit-benchmarks/src/bytecode_circuit.rs +++ b/circuit-benchmarks/src/bytecode_circuit.rs @@ -25,7 +25,7 @@ mod tests { use std::env::var; use zkevm_circuits::bytecode_circuit::bytecode_unroller::{unroll, UnrolledBytecode}; - use zkevm_circuits::bytecode_circuit::circuit::BytecodeCircuit; + use zkevm_circuits::bytecode_circuit::TestBytecodeCircuit; #[cfg_attr(not(feature = "benches"), ignore)] #[test] @@ -51,7 +51,7 @@ mod tests { let bytecodes_num: usize = max_bytecode_row_num / bytecode_len; // Create the circuit - let bytecode_circuit = BytecodeCircuit::::new( + let bytecode_circuit = TestBytecodeCircuit::::new( fillup_codebytes(bytecodes_num, bytecode_len), 2usize.pow(degree), ); @@ -88,7 +88,7 @@ mod tests { Challenge255, XorShiftRng, Blake2bWrite, G1Affine, Challenge255>, - BytecodeCircuit, + TestBytecodeCircuit, >( &general_params, &pk, diff --git a/circuit-benchmarks/src/copy_circuit.rs b/circuit-benchmarks/src/copy_circuit.rs index fc6d57c39e..e08e4aa8fd 100644 --- a/circuit-benchmarks/src/copy_circuit.rs +++ b/circuit-benchmarks/src/copy_circuit.rs @@ -25,7 +25,7 @@ mod tests { use rand_xorshift::XorShiftRng; use std::env::var; use zkevm_circuits::{ - copy_circuit::CopyCircuit, + copy_circuit::TestCopyCircuit, evm_circuit::witness::{block_convert, Block}, util::SubCircuit, }; @@ -52,7 +52,7 @@ mod tests { // Create the circuit let block = generate_full_events_block(degree); - let circuit = CopyCircuit::::new_from_block(&block); + let circuit = TestCopyCircuit::::new_from_block(&block); // Bench setup generation let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); @@ -79,7 +79,7 @@ mod tests { Challenge255, XorShiftRng, Blake2bWrite, G1Affine, Challenge255>, - CopyCircuit, + TestCopyCircuit, >(&general_params, &pk, &[circuit], &[], rng, &mut transcript) .expect("proof generation should not fail"); let proof = transcript.finalize(); diff --git a/circuit-benchmarks/src/evm_circuit.rs b/circuit-benchmarks/src/evm_circuit.rs index f055ad5873..aaf887261c 100644 --- a/circuit-benchmarks/src/evm_circuit.rs +++ b/circuit-benchmarks/src/evm_circuit.rs @@ -24,7 +24,7 @@ mod evm_circ_benches { use rand::SeedableRng; use rand_xorshift::XorShiftRng; use std::env::var; - use zkevm_circuits::evm_circuit::{witness::block_convert, EvmCircuit}; + use zkevm_circuits::evm_circuit::{witness::block_convert, TestEvmCircuit}; #[cfg_attr(not(feature = "benches"), ignore)] #[test] @@ -56,7 +56,7 @@ mod evm_circ_benches { let block = block_convert(&builder.block, &builder.code_db).unwrap(); - let circuit = EvmCircuit::::new(block); + let circuit = TestEvmCircuit::::new(block); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, @@ -87,7 +87,7 @@ mod evm_circ_benches { Challenge255, XorShiftRng, Blake2bWrite, G1Affine, Challenge255>, - EvmCircuit, + TestEvmCircuit, >( &general_params, &pk, diff --git a/circuit-benchmarks/src/exp_circuit.rs b/circuit-benchmarks/src/exp_circuit.rs index 2ad14f3812..28e1279178 100644 --- a/circuit-benchmarks/src/exp_circuit.rs +++ b/circuit-benchmarks/src/exp_circuit.rs @@ -27,7 +27,7 @@ mod tests { use std::env::var; use zkevm_circuits::{ evm_circuit::witness::{block_convert, Block}, - exp_circuit::ExpCircuit, + exp_circuit::TestExpCircuit, }; #[cfg_attr(not(feature = "benches"), ignore)] @@ -50,7 +50,7 @@ mod tests { let base = Word::from(132); let exponent = Word::from(27); let block = generate_full_events_block(degree, base, exponent); - let circuit = ExpCircuit::::new( + let circuit = TestExpCircuit::::new( block.exp_events.clone(), block.circuits_params.max_exp_steps, ); @@ -86,7 +86,7 @@ mod tests { Challenge255, XorShiftRng, Blake2bWrite, G1Affine, Challenge255>, - ExpCircuit, + TestExpCircuit, >( &general_params, &pk, diff --git a/circuit-benchmarks/src/packed_multi_keccak.rs b/circuit-benchmarks/src/packed_multi_keccak.rs index 1a3f6c4b12..e9268b98a2 100644 --- a/circuit-benchmarks/src/packed_multi_keccak.rs +++ b/circuit-benchmarks/src/packed_multi_keccak.rs @@ -21,7 +21,7 @@ mod tests { use rand::SeedableRng; use rand_xorshift::XorShiftRng; use std::env::var; - use zkevm_circuits::keccak_circuit::KeccakCircuit; + use zkevm_circuits::keccak_circuit::TestKeccakCircuit; #[cfg_attr(not(feature = "benches"), ignore)] #[test] @@ -41,7 +41,7 @@ mod tests { let inputs = vec![(0u8..135).collect::>(); 3]; // Create the circuit. Leave last dozens of rows for blinding. - let circuit = KeccakCircuit::new(2usize.pow(degree) - 64, inputs); + let circuit = TestKeccakCircuit::new(2usize.pow(degree) - 64, inputs); // Initialize the polynomial commitment parameters let mut rng = XorShiftRng::from_seed([ @@ -74,7 +74,7 @@ mod tests { Challenge255, XorShiftRng, Blake2bWrite, G1Affine, Challenge255>, - KeccakCircuit, + TestKeccakCircuit, >( &general_params, &pk, diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index a95848d960..3b02409e8e 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -11,7 +11,7 @@ lazy_static = "1.4" ethers = { version = "0.17.0", features = ["ethers-solc"] } serde_json = "1.0.66" serde = { version = "1.0.130", features = ["derive"] } -bus-mapping = { path = "../bus-mapping" } +bus-mapping = { path = "../bus-mapping" , features = ["test"] } eth-types = { path = "../eth-types" } zkevm-circuits = { path = "../zkevm-circuits", features = ["test"] } tokio = { version = "1.13", features = ["macros", "rt-multi-thread"] } diff --git a/integration-tests/src/integration_test_circuits.rs b/integration-tests/src/integration_test_circuits.rs index e33bd3d4fd..5eb08aa43a 100644 --- a/integration-tests/src/integration_test_circuits.rs +++ b/integration-tests/src/integration_test_circuits.rs @@ -28,14 +28,14 @@ use rand_xorshift::XorShiftRng; use std::{collections::HashMap, marker::PhantomData, sync::Mutex}; use tokio::sync::Mutex as TokioMutex; use zkevm_circuits::{ - bytecode_circuit::circuit::BytecodeCircuit, - copy_circuit::CopyCircuit, - evm_circuit::EvmCircuit, - exp_circuit::ExpCircuit, - keccak_circuit::KeccakCircuit, - state_circuit::StateCircuit, + bytecode_circuit::TestBytecodeCircuit, + copy_circuit::TestCopyCircuit, + evm_circuit::TestEvmCircuit, + exp_circuit::TestExpCircuit, + keccak_circuit::TestKeccakCircuit, + state_circuit::TestStateCircuit, super_circuit::SuperCircuit, - tx_circuit::TxCircuit, + tx_circuit::TestTxCircuit, util::SubCircuit, witness::{block_convert, Block}, }; @@ -95,27 +95,27 @@ lazy_static! { lazy_static! { /// Integration test for EVM circuit - pub static ref EVM_CIRCUIT_TEST: TokioMutex>> = + pub static ref EVM_CIRCUIT_TEST: TokioMutex>> = TokioMutex::new(IntegrationTest::new("EVM", EVM_CIRCUIT_DEGREE)); /// Integration test for State circuit - pub static ref STATE_CIRCUIT_TEST: TokioMutex>> = + pub static ref STATE_CIRCUIT_TEST: TokioMutex>> = TokioMutex::new(IntegrationTest::new("State", STATE_CIRCUIT_DEGREE)); /// Integration test for State circuit - pub static ref TX_CIRCUIT_TEST: TokioMutex>> = + pub static ref TX_CIRCUIT_TEST: TokioMutex>> = TokioMutex::new(IntegrationTest::new("Tx", TX_CIRCUIT_DEGREE)); /// Integration test for Bytecode circuit - pub static ref BYTECODE_CIRCUIT_TEST: TokioMutex>> = + pub static ref BYTECODE_CIRCUIT_TEST: TokioMutex>> = TokioMutex::new(IntegrationTest::new("Bytecode", BYTECODE_CIRCUIT_DEGREE)); /// Integration test for Copy circuit - pub static ref COPY_CIRCUIT_TEST: TokioMutex>> = + pub static ref COPY_CIRCUIT_TEST: TokioMutex>> = TokioMutex::new(IntegrationTest::new("Copy", COPY_CIRCUIT_DEGREE)); /// Integration test for Keccak circuit - pub static ref KECCAK_CIRCUIT_TEST: TokioMutex>> = + pub static ref KECCAK_CIRCUIT_TEST: TokioMutex>> = TokioMutex::new(IntegrationTest::new("Keccak", KECCAK_CIRCUIT_DEGREE)); /// Integration test for Copy circuit @@ -123,7 +123,7 @@ lazy_static! { TokioMutex::new(IntegrationTest::new("Super", SUPER_CIRCUIT_DEGREE)); /// Integration test for Exp circuit - pub static ref EXP_CIRCUIT_TEST: TokioMutex>> = + pub static ref EXP_CIRCUIT_TEST: TokioMutex>> = TokioMutex::new(IntegrationTest::new("Exp", EXP_CIRCUIT_DEGREE)); } diff --git a/zkevm-circuits/Cargo.toml b/zkevm-circuits/Cargo.toml index 0324f1970b..17cf8a03fb 100644 --- a/zkevm-circuits/Cargo.toml +++ b/zkevm-circuits/Cargo.toml @@ -52,6 +52,6 @@ serde_json = "1.0.78" [features] default = [] -test = ["ethers-signers", "mock"] +test = ["ethers-signers", "mock", "bus-mapping/test"] test-circuits = [] warn-unimplemented = ["eth-types/warn-unimplemented"] diff --git a/zkevm-circuits/src/bytecode_circuit.rs b/zkevm-circuits/src/bytecode_circuit.rs index a9db23040f..297e3a1622 100644 --- a/zkevm-circuits/src/bytecode_circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit.rs @@ -4,7 +4,12 @@ pub mod bytecode_unroller; /// Bytecode circuit pub mod circuit; +pub(crate) mod param; + +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +mod dev; /// Bytecode circuit tester #[cfg(any(feature = "test", test))] -pub mod dev; -pub(crate) mod param; +mod test; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +pub use dev::BytecodeCircuit as TestBytecodeCircuit; diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 41afc5bde4..87ea2351f5 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -22,9 +22,6 @@ use super::{ param::PUSH_TABLE_WIDTH, }; -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -use halo2_proofs::{circuit::SimpleFloorPlanner, plonk::Circuit}; - #[derive(Clone, Debug)] /// Bytecode circuit configuration pub struct BytecodeCircuitConfig { @@ -804,294 +801,3 @@ impl SubCircuit for BytecodeCircuit { config.assign_internal(layouter, self.size, &self.bytecodes, challenges, false) } } - -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -impl Circuit for BytecodeCircuit { - type Config = (BytecodeCircuitConfig, Challenges); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let bytecode_table = BytecodeTable::construct(meta); - let keccak_table = KeccakTable::construct(meta); - let challenges = Challenges::construct(meta); - - let config = { - let challenges = challenges.exprs(meta); - BytecodeCircuitConfig::new( - meta, - BytecodeCircuitConfigArgs { - bytecode_table, - keccak_table, - challenges, - }, - ) - }; - - (config, challenges) - } - - fn synthesize( - &self, - (config, challenges): Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let challenges = challenges.values(&mut layouter); - - config.keccak_table.dev_load( - &mut layouter, - self.bytecodes.iter().map(|b| &b.bytes), - &challenges, - )?; - self.synthesize_sub(&config, &challenges, &mut layouter)?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - bytecode_circuit::{bytecode_unroller::BytecodeRow, dev::test_bytecode_circuit_unrolled}, - util::{is_push, keccak}, - }; - use bus_mapping::evm::OpcodeId; - use eth_types::{Bytecode, Word}; - use halo2_proofs::halo2curves::bn256::Fr; - - /// Verify unrolling code - #[test] - fn bytecode_unrolling() { - let k = 10; - let mut rows = vec![]; - let mut bytecode = Bytecode::default(); - // First add all non-push bytes, which should all be seen as code - for byte in 0u8..=255u8 { - if !is_push(byte) { - bytecode.write(byte, true); - rows.push(BytecodeRow { - code_hash: Word::zero(), - tag: Fr::from(BytecodeFieldTag::Byte as u64), - index: Fr::from(rows.len() as u64), - is_code: Fr::from(true as u64), - value: Fr::from(byte as u64), - }); - } - } - // Now add the different push ops - for n in 1..=32 { - let data_byte = OpcodeId::PUSH32.as_u8(); - bytecode.push( - n, - Word::from_little_endian(&vec![data_byte; n as usize][..]), - ); - rows.push(BytecodeRow { - code_hash: Word::zero(), - tag: Fr::from(BytecodeFieldTag::Byte as u64), - index: Fr::from(rows.len() as u64), - is_code: Fr::from(true as u64), - value: Fr::from(OpcodeId::PUSH1.as_u64() + ((n - 1) as u64)), - }); - for _ in 0..n { - rows.push(BytecodeRow { - code_hash: Word::zero(), - tag: Fr::from(BytecodeFieldTag::Byte as u64), - index: Fr::from(rows.len() as u64), - is_code: Fr::from(false as u64), - value: Fr::from(data_byte as u64), - }); - } - } - // Set the code_hash of the complete bytecode in the rows - let code_hash = keccak(&bytecode.to_vec()[..]); - for row in rows.iter_mut() { - row.code_hash = code_hash; - } - rows.insert( - 0, - BytecodeRow { - code_hash, - tag: Fr::from(BytecodeFieldTag::Header as u64), - index: Fr::zero(), - is_code: Fr::zero(), - value: Fr::from(bytecode.to_vec().len() as u64), - }, - ); - // Unroll the bytecode - let unrolled = unroll(bytecode.to_vec()); - // Check if the bytecode was unrolled correctly - assert_eq!( - UnrolledBytecode { - bytes: bytecode.to_vec(), - rows, - }, - unrolled, - ); - // Verify the unrolling in the circuit - test_bytecode_circuit_unrolled::(k, vec![unrolled], true); - } - - /// Tests a fully empty circuit - #[test] - fn bytecode_empty() { - let k = 9; - test_bytecode_circuit_unrolled::(k, vec![unroll(vec![])], true); - } - - #[test] - fn bytecode_simple() { - let k = 9; - let bytecodes = vec![unroll(vec![7u8]), unroll(vec![6u8]), unroll(vec![5u8])]; - test_bytecode_circuit_unrolled::(k, bytecodes, true); - } - - /// Tests a fully full circuit - #[test] - fn bytecode_full() { - let k = 9; - test_bytecode_circuit_unrolled::(k, vec![unroll(vec![7u8; 2usize.pow(k) - 8])], true); - } - - #[test] - fn bytecode_last_row_with_byte() { - let k = 9; - // Last row must be a padding row, so we have one row less for actual bytecode - test_bytecode_circuit_unrolled::(k, vec![unroll(vec![7u8; 2usize.pow(k) - 7])], false); - } - - /// Tests a circuit with incomplete bytecode - #[test] - fn bytecode_incomplete() { - let k = 9; - test_bytecode_circuit_unrolled::(k, vec![unroll(vec![7u8; 2usize.pow(k) + 1])], false); - } - - /// Tests multiple bytecodes in a single circuit - #[test] - fn bytecode_push() { - let k = 9; - test_bytecode_circuit_unrolled::( - k, - vec![ - unroll(vec![]), - unroll(vec![OpcodeId::PUSH32.as_u8()]), - unroll(vec![OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8()]), - unroll(vec![OpcodeId::ADD.as_u8(), OpcodeId::PUSH32.as_u8()]), - unroll(vec![ - OpcodeId::ADD.as_u8(), - OpcodeId::PUSH32.as_u8(), - OpcodeId::ADD.as_u8(), - ]), - ], - true, - ); - } - - /// Test invalid code_hash data - #[test] - fn bytecode_invalid_hash_data() { - let k = 9; - let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; - let unrolled = unroll(bytecode); - test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); - // Change the code_hash on the first position (header row) - { - let mut invalid = unrolled; - invalid.rows[0].code_hash += Word::one(); - trace!("bytecode_invalid_hash_data: Change the code_hash on the first position"); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); - } - // TODO: other rows code_hash are ignored by the witness generation, to - // test other rows invalid code_hash, we would need to inject an evil - // witness. - } - - /// Test invalid index - #[test] - #[ignore] - fn bytecode_invalid_index() { - let k = 9; - let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; - let unrolled = unroll(bytecode); - test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); - // Start the index at 1 - { - let mut invalid = unrolled.clone(); - for row in invalid.rows.iter_mut() { - row.index += Fr::one(); - } - test_bytecode_circuit_unrolled::(k, vec![invalid], false); - } - // Don't increment an index once - { - let mut invalid = unrolled; - invalid.rows.last_mut().unwrap().index -= Fr::one(); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); - } - } - - /// Test invalid byte data - #[test] - fn bytecode_invalid_byte_data() { - let k = 9; - let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; - let unrolled = unroll(bytecode); - test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); - // Change the first byte - { - let mut invalid = unrolled.clone(); - invalid.rows[1].value = Fr::from(9u64); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); - } - // Change a byte on another position - { - let mut invalid = unrolled.clone(); - invalid.rows[5].value = Fr::from(6u64); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); - } - // Set a byte value out of range - { - let mut invalid = unrolled; - invalid.rows[3].value = Fr::from(256u64); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); - } - } - - /// Test invalid is_code data - #[test] - fn bytecode_invalid_is_code() { - let k = 9; - let bytecode = vec![ - OpcodeId::ADD.as_u8(), - OpcodeId::PUSH1.as_u8(), - OpcodeId::PUSH1.as_u8(), - OpcodeId::SUB.as_u8(), - OpcodeId::PUSH7.as_u8(), - OpcodeId::ADD.as_u8(), - OpcodeId::PUSH6.as_u8(), - ]; - let unrolled = unroll(bytecode); - test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); - // Mark the 3rd byte as code (is push data from the first PUSH1) - { - let mut invalid = unrolled.clone(); - invalid.rows[3].is_code = Fr::one(); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); - } - // Mark the 4rd byte as data (is code) - { - let mut invalid = unrolled.clone(); - invalid.rows[4].is_code = Fr::zero(); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); - } - // Mark the 7th byte as code (is data for the PUSH7) - { - let mut invalid = unrolled; - invalid.rows[7].is_code = Fr::one(); - test_bytecode_circuit_unrolled::(k, vec![invalid], false); - } - } -} diff --git a/zkevm-circuits/src/bytecode_circuit/dev.rs b/zkevm-circuits/src/bytecode_circuit/dev.rs index d4610c32d0..dd33c563ab 100644 --- a/zkevm-circuits/src/bytecode_circuit/dev.rs +++ b/zkevm-circuits/src/bytecode_circuit/dev.rs @@ -1,49 +1,57 @@ -use super::{ - bytecode_unroller::{unroll, UnrolledBytecode}, - circuit::BytecodeCircuit, -}; +pub use super::circuit::BytecodeCircuit; +use crate::{ + bytecode_circuit::circuit::{BytecodeCircuitConfig, BytecodeCircuitConfigArgs}, + table::{BytecodeTable, KeccakTable}, + util::{Challenges, SubCircuit, SubCircuitConfig}, +}; use eth_types::Field; +use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + plonk::{Circuit, ConstraintSystem, Error}, +}; -use halo2_proofs::dev::MockProver; -use log::error; +impl Circuit for BytecodeCircuit { + type Config = (BytecodeCircuitConfig, Challenges); + type FloorPlanner = SimpleFloorPlanner; -impl BytecodeCircuit { - /// Verify that the selected bytecode fulfills the circuit - pub fn verify_raw(k: u32, bytecodes: Vec>) { - let unrolled: Vec<_> = bytecodes.iter().map(|b| unroll(b.clone())).collect(); - Self::verify(k, unrolled, true); + fn without_witnesses(&self) -> Self { + Self::default() } - pub(crate) fn verify(k: u32, bytecodes: Vec>, success: bool) { - let circuit = BytecodeCircuit::::new(bytecodes, 2usize.pow(k)); - - let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); - let result = prover.verify(); - if let Err(failures) = &result { - for failure in failures.iter() { - error!("{}", failure); - } - } - assert_eq!(result.is_ok(), success); + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let bytecode_table = BytecodeTable::construct(meta); + let keccak_table = KeccakTable::construct(meta); + let challenges = Challenges::construct(meta); + + let config = { + let challenges = challenges.exprs(meta); + BytecodeCircuitConfig::new( + meta, + BytecodeCircuitConfigArgs { + bytecode_table, + keccak_table, + challenges, + }, + ) + }; + + (config, challenges) } -} -/// Test bytecode circuit with unrolled bytecode -pub fn test_bytecode_circuit_unrolled( - k: u32, - bytecodes: Vec>, - success: bool, -) { - let circuit = BytecodeCircuit::::new(bytecodes, 2usize.pow(k)); - - let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); - let result = prover.verify_par(); - if let Err(failures) = &result { - for failure in failures.iter() { - error!("{}", failure); - } + fn synthesize( + &self, + (config, challenges): Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let challenges = challenges.values(&mut layouter); + + config.keccak_table.dev_load( + &mut layouter, + self.bytecodes.iter().map(|b| &b.bytes), + &challenges, + )?; + self.synthesize_sub(&config, &challenges, &mut layouter)?; + Ok(()) } - let error_msg = if success { "valid" } else { "invalid" }; - assert_eq!(result.is_ok(), success, "proof must be {}", error_msg); } diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs new file mode 100644 index 0000000000..85ec8f80df --- /dev/null +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -0,0 +1,283 @@ +#![allow(unused_imports)] +use crate::{ + bytecode_circuit::{bytecode_unroller::*, circuit::BytecodeCircuit}, + table::BytecodeFieldTag, + util::{is_push, keccak, Challenges, SubCircuit}, +}; +use bus_mapping::evm::OpcodeId; +use eth_types::{Bytecode, Field, Word}; +use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; +use log::error; + +impl BytecodeCircuit { + /// Verify that the selected bytecode fulfills the circuit + pub fn verify_raw(k: u32, bytecodes: Vec>) { + let unrolled: Vec<_> = bytecodes.iter().map(|b| unroll(b.clone())).collect(); + Self::verify(k, unrolled, true); + } + + pub(crate) fn verify(k: u32, bytecodes: Vec>, success: bool) { + let circuit = BytecodeCircuit::::new(bytecodes, 2usize.pow(k)); + + let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); + let result = prover.verify(); + if let Err(failures) = &result { + for failure in failures.iter() { + error!("{}", failure); + } + } + assert_eq!(result.is_ok(), success); + } +} + +/// Test bytecode circuit with unrolled bytecode +pub fn test_bytecode_circuit_unrolled( + k: u32, + bytecodes: Vec>, + success: bool, +) { + let circuit = BytecodeCircuit::::new(bytecodes, 2usize.pow(k)); + + let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); + let result = prover.verify_par(); + if let Err(failures) = &result { + for failure in failures.iter() { + error!("{}", failure); + } + } + let error_msg = if success { "valid" } else { "invalid" }; + assert_eq!(result.is_ok(), success, "proof must be {}", error_msg); +} + +/// Verify unrolling code +#[test] +fn bytecode_unrolling() { + let k = 10; + let mut rows = vec![]; + let mut bytecode = Bytecode::default(); + // First add all non-push bytes, which should all be seen as code + for byte in 0u8..=255u8 { + if !is_push(byte) { + bytecode.write(byte, true); + rows.push(BytecodeRow { + code_hash: Word::zero(), + tag: Fr::from(BytecodeFieldTag::Byte as u64), + index: Fr::from(rows.len() as u64), + is_code: Fr::from(true as u64), + value: Fr::from(byte as u64), + }); + } + } + // Now add the different push ops + for n in 1..=32 { + let data_byte = OpcodeId::PUSH32.as_u8(); + bytecode.push( + n, + Word::from_little_endian(&vec![data_byte; n as usize][..]), + ); + rows.push(BytecodeRow { + code_hash: Word::zero(), + tag: Fr::from(BytecodeFieldTag::Byte as u64), + index: Fr::from(rows.len() as u64), + is_code: Fr::from(true as u64), + value: Fr::from(OpcodeId::PUSH1.as_u64() + ((n - 1) as u64)), + }); + for _ in 0..n { + rows.push(BytecodeRow { + code_hash: Word::zero(), + tag: Fr::from(BytecodeFieldTag::Byte as u64), + index: Fr::from(rows.len() as u64), + is_code: Fr::from(false as u64), + value: Fr::from(data_byte as u64), + }); + } + } + // Set the code_hash of the complete bytecode in the rows + let code_hash = keccak(&bytecode.to_vec()[..]); + for row in rows.iter_mut() { + row.code_hash = code_hash; + } + rows.insert( + 0, + BytecodeRow { + code_hash, + tag: Fr::from(BytecodeFieldTag::Header as u64), + index: Fr::zero(), + is_code: Fr::zero(), + value: Fr::from(bytecode.to_vec().len() as u64), + }, + ); + // Unroll the bytecode + let unrolled = unroll(bytecode.to_vec()); + // Check if the bytecode was unrolled correctly + assert_eq!( + UnrolledBytecode { + bytes: bytecode.to_vec(), + rows, + }, + unrolled, + ); + // Verify the unrolling in the circuit + test_bytecode_circuit_unrolled::(k, vec![unrolled], true); +} + +/// Tests a fully empty circuit +#[test] +fn bytecode_empty() { + let k = 9; + test_bytecode_circuit_unrolled::(k, vec![unroll(vec![])], true); +} + +#[test] +fn bytecode_simple() { + let k = 9; + let bytecodes = vec![unroll(vec![7u8]), unroll(vec![6u8]), unroll(vec![5u8])]; + test_bytecode_circuit_unrolled::(k, bytecodes, true); +} + +/// Tests a fully full circuit +#[test] +fn bytecode_full() { + let k = 9; + test_bytecode_circuit_unrolled::(k, vec![unroll(vec![7u8; 2usize.pow(k) - 8])], true); +} + +#[test] +fn bytecode_last_row_with_byte() { + let k = 9; + // Last row must be a padding row, so we have one row less for actual bytecode + test_bytecode_circuit_unrolled::(k, vec![unroll(vec![7u8; 2usize.pow(k) - 7])], false); +} + +/// Tests a circuit with incomplete bytecode +#[test] +fn bytecode_incomplete() { + let k = 9; + test_bytecode_circuit_unrolled::(k, vec![unroll(vec![7u8; 2usize.pow(k) + 1])], false); +} + +/// Tests multiple bytecodes in a single circuit +#[test] +fn bytecode_push() { + let k = 9; + test_bytecode_circuit_unrolled::( + k, + vec![ + unroll(vec![]), + unroll(vec![OpcodeId::PUSH32.as_u8()]), + unroll(vec![OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8()]), + unroll(vec![OpcodeId::ADD.as_u8(), OpcodeId::PUSH32.as_u8()]), + unroll(vec![ + OpcodeId::ADD.as_u8(), + OpcodeId::PUSH32.as_u8(), + OpcodeId::ADD.as_u8(), + ]), + ], + true, + ); +} + +/// Test invalid code_hash data +#[test] +fn bytecode_invalid_hash_data() { + let k = 9; + let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; + let unrolled = unroll(bytecode); + test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); + // Change the code_hash on the first position (header row) + { + let mut invalid = unrolled; + invalid.rows[0].code_hash += Word::one(); + log::trace!("bytecode_invalid_hash_data: Change the code_hash on the first position"); + test_bytecode_circuit_unrolled::(k, vec![invalid], false); + } + // TODO: other rows code_hash are ignored by the witness generation, to + // test other rows invalid code_hash, we would need to inject an evil + // witness. +} + +/// Test invalid index +#[test] +#[ignore] +fn bytecode_invalid_index() { + let k = 9; + let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; + let unrolled = unroll(bytecode); + test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); + // Start the index at 1 + { + let mut invalid = unrolled.clone(); + for row in invalid.rows.iter_mut() { + row.index += Fr::one(); + } + test_bytecode_circuit_unrolled::(k, vec![invalid], false); + } + // Don't increment an index once + { + let mut invalid = unrolled; + invalid.rows.last_mut().unwrap().index -= Fr::one(); + test_bytecode_circuit_unrolled::(k, vec![invalid], false); + } +} + +/// Test invalid byte data +#[test] +fn bytecode_invalid_byte_data() { + let k = 9; + let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128]; + let unrolled = unroll(bytecode); + test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); + // Change the first byte + { + let mut invalid = unrolled.clone(); + invalid.rows[1].value = Fr::from(9u64); + test_bytecode_circuit_unrolled::(k, vec![invalid], false); + } + // Change a byte on another position + { + let mut invalid = unrolled.clone(); + invalid.rows[5].value = Fr::from(6u64); + test_bytecode_circuit_unrolled::(k, vec![invalid], false); + } + // Set a byte value out of range + { + let mut invalid = unrolled; + invalid.rows[3].value = Fr::from(256u64); + test_bytecode_circuit_unrolled::(k, vec![invalid], false); + } +} + +/// Test invalid is_code data +#[test] +fn bytecode_invalid_is_code() { + let k = 9; + let bytecode = vec![ + OpcodeId::ADD.as_u8(), + OpcodeId::PUSH1.as_u8(), + OpcodeId::PUSH1.as_u8(), + OpcodeId::SUB.as_u8(), + OpcodeId::PUSH7.as_u8(), + OpcodeId::ADD.as_u8(), + OpcodeId::PUSH6.as_u8(), + ]; + let unrolled = unroll(bytecode); + test_bytecode_circuit_unrolled::(k, vec![unrolled.clone()], true); + // Mark the 3rd byte as code (is push data from the first PUSH1) + { + let mut invalid = unrolled.clone(); + invalid.rows[3].is_code = Fr::one(); + test_bytecode_circuit_unrolled::(k, vec![invalid], false); + } + // Mark the 4rd byte as data (is code) + { + let mut invalid = unrolled.clone(); + invalid.rows[4].is_code = Fr::zero(); + test_bytecode_circuit_unrolled::(k, vec![invalid], false); + } + // Mark the 7th byte as code (is data for the PUSH7) + { + let mut invalid = unrolled; + invalid.rows[7].is_code = Fr::one(); + test_bytecode_circuit_unrolled::(k, vec![invalid], false); + } +} diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index 03e556cd28..57a83fded2 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -1,9 +1,18 @@ //! The Copy circuit implements constraints and lookups for read-write steps for //! copied bytes while execution opcodes such as CALLDATACOPY, CODECOPY, LOGS, //! etc. +pub(crate) mod util; -use bus_mapping::circuit_input_builder::{CopyDataType, CopyEvent, NumberOrHash}; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +mod dev; +#[cfg(any(feature = "test", test))] +mod test; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +pub use dev::CopyCircuit as TestCopyCircuit; + +use bus_mapping::circuit_input_builder::{CopyDataType, CopyEvent}; use eth_types::{Field, Word}; + use gadgets::{ binary_number::BinaryNumberChip, less_than::{LtChip, LtConfig, LtInstruction}, @@ -18,7 +27,7 @@ use itertools::Itertools; use std::{collections::HashMap, marker::PhantomData}; use crate::{ - evm_circuit::util::{constraint_builder::BaseConstraintBuilder, rlc}, + evm_circuit::util::constraint_builder::BaseConstraintBuilder, table::{ BytecodeFieldTag, BytecodeTable, CopyTable, LookupTable, RwTable, RwTableTag, TxContextFieldTag, TxTable, @@ -28,30 +37,6 @@ use crate::{ witness::{Bytecode, RwMap, Transaction}, }; -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -use halo2_proofs::{ - circuit::SimpleFloorPlanner, - plonk::{Challenge, Circuit}, -}; - -/// Encode the type `NumberOrHash` into a field element -pub fn number_or_hash_to_field(v: &NumberOrHash, challenge: Value) -> Value { - match v { - NumberOrHash::Number(n) => Value::known(F::from(*n as u64)), - NumberOrHash::Hash(h) => { - // since code hash in the bytecode table is represented in - // the little-endian form, we reverse the big-endian bytes - // of H256. - let le_bytes = { - let mut b = h.to_fixed_bytes(); - b.reverse(); - b - }; - challenge.map(|challenge| rlc::value(&le_bytes, challenge)) - } - } -} - /// The rw table shared between evm circuit and state circuit #[derive(Clone, Debug)] pub struct CopyCircuitConfig { @@ -785,427 +770,6 @@ impl SubCircuit for CopyCircuit { } } -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -impl Circuit for CopyCircuit { - type Config = (CopyCircuitConfig, Challenges); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let tx_table = TxTable::construct(meta); - let rw_table = RwTable::construct(meta); - let bytecode_table = BytecodeTable::construct(meta); - let q_enable = meta.fixed_column(); - let copy_table = CopyTable::construct(meta, q_enable); - let challenges = Challenges::construct(meta); - let challenge_exprs = challenges.exprs(meta); - - ( - CopyCircuitConfig::new( - meta, - CopyCircuitConfigArgs { - tx_table, - rw_table, - bytecode_table, - copy_table, - q_enable, - challenges: challenge_exprs, - }, - ), - challenges, - ) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), halo2_proofs::plonk::Error> { - let challenge_values = config.1.values(&mut layouter); - - config.0.tx_table.load( - &mut layouter, - &self.external_data.txs, - self.external_data.max_txs, - self.external_data.max_calldata, - &challenge_values, - )?; - - config.0.rw_table.load( - &mut layouter, - &self.external_data.rws.table_assignments(), - self.external_data.max_rws, - challenge_values.evm_word(), - )?; - - config.0.bytecode_table.load( - &mut layouter, - self.external_data.bytecodes.values(), - &challenge_values, - )?; - self.synthesize_sub(&config.0, &challenge_values, &mut layouter) - } -} - -/// Dev helpers -#[cfg(any(feature = "test", test))] -pub mod dev { - use crate::{copy_circuit::*, witness::Block}; - use halo2_proofs::dev::{MockProver, VerifyFailure}; - - /// Test copy circuit from copy events and test data - pub fn test_copy_circuit( - k: u32, - copy_events: Vec, - max_copy_rows: usize, - external_data: ExternalData, - ) -> Result<(), Vec> { - let circuit = - CopyCircuit::::new_with_external_data(copy_events, max_copy_rows, external_data); - - let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); - prover.verify_par() - } - - /// Test copy circuit with the provided block witness - pub fn test_copy_circuit_from_block( - k: u32, - block: Block, - ) -> Result<(), Vec> { - test_copy_circuit::( - k, - block.copy_events, - block.circuits_params.max_copy_rows, - ExternalData { - max_txs: block.circuits_params.max_txs, - max_calldata: block.circuits_params.max_calldata, - txs: block.txs, - max_rws: block.circuits_params.max_rws, - rws: block.rws, - bytecodes: block.bytecodes, - }, - ) - } -} - -#[cfg(test)] -mod tests { - use super::dev::test_copy_circuit_from_block; - use crate::{ - copy_circuit::CopyCircuit, - evm_circuit::{test::rand_bytes, witness::block_convert}, - }; - use bus_mapping::{ - circuit_input_builder::{CircuitInputBuilder, CircuitsParams}, - evm::{gen_sha3_code, MemoryKind}, - mock::BlockData, - }; - use eth_types::{bytecode, geth_types::GethData, ToWord, Word}; - use halo2_proofs::{ - dev::{MockProver, VerifyFailure}, - halo2curves::bn256::Fr, - }; - use mock::{test_ctx::helpers::account_0_code_account_1_no_code, TestContext, MOCK_ACCOUNTS}; - use pretty_assertions::assert_eq; - - fn gen_calldatacopy_data() -> CircuitInputBuilder { - let length = 0x0fffusize; - let code = bytecode! { - PUSH32(Word::from(length)) - PUSH32(Word::from(0x00)) - PUSH32(Word::from(0x00)) - CALLDATACOPY - STOP - }; - let calldata = rand_bytes(length); - let test_ctx = TestContext::<2, 1>::new( - None, - account_0_code_account_1_no_code(code), - |mut txs, accs| { - txs[0] - .from(accs[1].address) - .to(accs[0].address) - .input(calldata.into()); - }, - |block, _txs| block.number(0xcafeu64), - ) - .unwrap(); - let block: GethData = test_ctx.into(); - let mut builder = BlockData::new_from_geth_data_with_params( - block.clone(), - CircuitsParams { - max_rws: 8192, - max_copy_rows: 8192 + 2, - max_calldata: 5000, - ..Default::default() - }, - ) - .new_circuit_input_builder(); - builder - .handle_block(&block.eth_block, &block.geth_traces) - .unwrap(); - builder - } - - fn gen_codecopy_data() -> CircuitInputBuilder { - let code = bytecode! { - PUSH32(Word::from(0x20)) - PUSH32(Word::from(0x00)) - PUSH32(Word::from(0x00)) - CODECOPY - STOP - }; - let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(); - let block: GethData = test_ctx.into(); - let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); - builder - .handle_block(&block.eth_block, &block.geth_traces) - .unwrap(); - builder - } - - fn gen_extcodecopy_data() -> CircuitInputBuilder { - let external_address = MOCK_ACCOUNTS[0]; - let code = bytecode! { - PUSH1(0x30usize) - PUSH1(0x0usize) - PUSH1(0x0usize) - PUSH20(external_address.to_word()) - EXTCODECOPY - STOP - }; - let code_ext = rand_bytes(0x0fffusize); - let test_ctx = TestContext::<3, 1>::new( - None, - |accs| { - accs[0].address(MOCK_ACCOUNTS[1]).code(code.clone()); - - accs[1].address(external_address).code(code_ext.clone()); - - accs[2] - .address(MOCK_ACCOUNTS[2]) - .balance(Word::from(1u64 << 20)); - }, - |mut txs, accs| { - txs[0].to(accs[0].address).from(accs[2].address); - }, - |block, _tx| block.number(0xcafeu64), - ) - .unwrap(); - let block: GethData = test_ctx.into(); - let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); - builder - .handle_block(&block.eth_block, &block.geth_traces) - .unwrap(); - builder - } - - fn gen_sha3_data() -> CircuitInputBuilder { - let (code, _) = gen_sha3_code(0x20, 0x200, MemoryKind::EqualToSize); - let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(); - let block: GethData = test_ctx.into(); - let mut builder = BlockData::new_from_geth_data_with_params( - block.clone(), - CircuitsParams { - max_rws: 2000, - max_copy_rows: 0x200 * 2 + 2, - ..Default::default() - }, - ) - .new_circuit_input_builder(); - builder - .handle_block(&block.eth_block, &block.geth_traces) - .unwrap(); - builder - } - - fn gen_tx_log_data() -> CircuitInputBuilder { - let code = bytecode! { - PUSH32(200) // value - PUSH32(0) // offset - MSTORE - PUSH32(Word::MAX) // topic - PUSH1(32) // length - PUSH1(0) // offset - LOG1 - STOP - }; - let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(); - let block: GethData = test_ctx.into(); - let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); - builder - .handle_block(&block.eth_block, &block.geth_traces) - .unwrap(); - builder - } - - #[test] - fn copy_circuit_valid_calldatacopy() { - let builder = gen_calldatacopy_data(); - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - assert_eq!(test_copy_circuit_from_block(14, block), Ok(())); - } - - #[test] - fn copy_circuit_valid_codecopy() { - let builder = gen_codecopy_data(); - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - assert_eq!(test_copy_circuit_from_block(10, block), Ok(())); - } - - #[test] - fn copy_circuit_valid_extcodecopy() { - let builder = gen_extcodecopy_data(); - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - assert_eq!(test_copy_circuit_from_block(14, block), Ok(())); - } - - #[test] - fn copy_circuit_valid_sha3() { - let builder = gen_sha3_data(); - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - assert_eq!(test_copy_circuit_from_block(14, block), Ok(())); - } - - #[test] - fn copy_circuit_valid_tx_log() { - let builder = gen_tx_log_data(); - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - assert_eq!(test_copy_circuit_from_block(10, block), Ok(())); - } - - #[test] - fn copy_circuit_invalid_calldatacopy() { - let mut builder = gen_calldatacopy_data(); - - // modify first byte of first copy event - builder.block.copy_events[0].bytes[0].0 = - builder.block.copy_events[0].bytes[0].0.wrapping_add(1); - - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - - assert_error_matches( - test_copy_circuit_from_block(14, block), - vec!["Memory lookup", "Tx calldata lookup"], - ); - } - - #[test] - fn copy_circuit_invalid_codecopy() { - let mut builder = gen_codecopy_data(); - - // modify first byte of first copy event - builder.block.copy_events[0].bytes[0].0 = - builder.block.copy_events[0].bytes[0].0.wrapping_add(1); - - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - - assert_error_matches( - test_copy_circuit_from_block(10, block), - vec!["Memory lookup", "Bytecode lookup"], - ); - } - - #[test] - fn copy_circuit_invalid_extcodecopy() { - let mut builder = gen_extcodecopy_data(); - - // modify first byte of first copy event - builder.block.copy_events[0].bytes[0].0 = - builder.block.copy_events[0].bytes[0].0.wrapping_add(1); - - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - - assert_error_matches( - test_copy_circuit_from_block(14, block), - vec!["Memory lookup", "Bytecode lookup"], - ); - } - - #[test] - fn copy_circuit_invalid_sha3() { - let mut builder = gen_sha3_data(); - - // modify first byte of first copy event - builder.block.copy_events[0].bytes[0].0 = - builder.block.copy_events[0].bytes[0].0.wrapping_add(1); - - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - - assert_error_matches( - test_copy_circuit_from_block(14, block), - vec!["Memory lookup"], - ); - } - - #[test] - fn copy_circuit_invalid_tx_log() { - let mut builder = gen_tx_log_data(); - - // modify first byte of first copy event - builder.block.copy_events[0].bytes[0].0 = - builder.block.copy_events[0].bytes[0].0.wrapping_add(1); - - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - - assert_error_matches( - test_copy_circuit_from_block(10, block), - vec!["Memory lookup", "TxLog lookup"], - ); - } - - #[test] - fn variadic_size_check() { - let builder = gen_tx_log_data(); - let block1 = block_convert::(&builder.block, &builder.code_db).unwrap(); - - let block: GethData = TestContext::<0, 0>::new(None, |_| {}, |_, _| {}, |b, _| b) - .unwrap() - .into(); - let mut builder = - BlockData::new_from_geth_data_with_params(block.clone(), CircuitsParams::default()) - .new_circuit_input_builder(); - builder - .handle_block(&block.eth_block, &block.geth_traces) - .unwrap(); - let block2 = block_convert::(&builder.block, &builder.code_db).unwrap(); - - let circuit = - CopyCircuit::::new(block1.copy_events, block1.circuits_params.max_copy_rows); - let prover1 = MockProver::::run(14, &circuit, vec![]).unwrap(); - - let circuit = CopyCircuit::::new( - block2.copy_events.clone(), - block2.circuits_params.max_copy_rows, - ); - let prover2 = MockProver::::run(14, &circuit, vec![]).unwrap(); - - assert_eq!(prover1.fixed(), prover2.fixed()); - assert_eq!(prover1.permutation(), prover2.permutation()); - } - - fn assert_error_matches(result: Result<(), Vec>, names: Vec<&str>) { - let errors = result.expect_err("result is not an error"); - assert_eq!(errors.len(), names.len(), "{:?}", errors); - for i in 0..names.len() { - match &errors[i] { - VerifyFailure::Lookup { - name: lookup_name, .. - } => { - assert_eq!(lookup_name, &names[i]) - } - VerifyFailure::ConstraintNotSatisfied { .. } => panic!(), - VerifyFailure::CellNotAssigned { .. } => panic!(), - VerifyFailure::ConstraintPoisoned { .. } => panic!(), - VerifyFailure::Permutation { .. } => panic!(), - } - } - } -} - #[cfg(test)] mod copy_circuit_stats { use crate::{ diff --git a/zkevm-circuits/src/copy_circuit/dev.rs b/zkevm-circuits/src/copy_circuit/dev.rs new file mode 100644 index 0000000000..9671989777 --- /dev/null +++ b/zkevm-circuits/src/copy_circuit/dev.rs @@ -0,0 +1,76 @@ +pub use super::CopyCircuit; + +use crate::{ + copy_circuit::{CopyCircuitConfig, CopyCircuitConfigArgs}, + table::{BytecodeTable, CopyTable, RwTable, TxTable}, + util::{Challenges, SubCircuit, SubCircuitConfig}, +}; +use eth_types::Field; +use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + plonk::{Challenge, Circuit, ConstraintSystem, Error}, +}; + +impl Circuit for CopyCircuit { + type Config = (CopyCircuitConfig, Challenges); + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let tx_table = TxTable::construct(meta); + let rw_table = RwTable::construct(meta); + let bytecode_table = BytecodeTable::construct(meta); + let q_enable = meta.fixed_column(); + let copy_table = CopyTable::construct(meta, q_enable); + let challenges = Challenges::construct(meta); + let challenge_exprs = challenges.exprs(meta); + + ( + CopyCircuitConfig::new( + meta, + CopyCircuitConfigArgs { + tx_table, + rw_table, + bytecode_table, + copy_table, + q_enable, + challenges: challenge_exprs, + }, + ), + challenges, + ) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let challenge_values = config.1.values(&mut layouter); + + config.0.tx_table.load( + &mut layouter, + &self.external_data.txs, + self.external_data.max_txs, + self.external_data.max_calldata, + &challenge_values, + )?; + + config.0.rw_table.load( + &mut layouter, + &self.external_data.rws.table_assignments(), + self.external_data.max_rws, + challenge_values.evm_word(), + )?; + + config.0.bytecode_table.load( + &mut layouter, + self.external_data.bytecodes.values(), + &challenge_values, + )?; + self.synthesize_sub(&config.0, &challenge_values, &mut layouter) + } +} diff --git a/zkevm-circuits/src/copy_circuit/test.rs b/zkevm-circuits/src/copy_circuit/test.rs new file mode 100644 index 0000000000..4fba9ce756 --- /dev/null +++ b/zkevm-circuits/src/copy_circuit/test.rs @@ -0,0 +1,345 @@ +#![allow(unused_imports)] + +use crate::{ + copy_circuit::*, + evm_circuit::{test::rand_bytes, witness::block_convert}, + witness::Block, +}; +use bus_mapping::{ + circuit_input_builder::{CircuitInputBuilder, CircuitsParams}, + evm::{gen_sha3_code, MemoryKind}, + mock::BlockData, +}; +use eth_types::{bytecode, geth_types::GethData, ToWord, Word}; +use halo2_proofs::{ + dev::{MockProver, VerifyFailure}, + halo2curves::bn256::Fr, +}; +use mock::{test_ctx::helpers::account_0_code_account_1_no_code, TestContext, MOCK_ACCOUNTS}; + +/// Test copy circuit from copy events and test data +pub fn test_copy_circuit( + k: u32, + copy_events: Vec, + max_copy_rows: usize, + external_data: ExternalData, +) -> Result<(), Vec> { + let circuit = + CopyCircuit::::new_with_external_data(copy_events, max_copy_rows, external_data); + + let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); + prover.verify_par() +} + +/// Test copy circuit with the provided block witness +pub fn test_copy_circuit_from_block( + k: u32, + block: Block, +) -> Result<(), Vec> { + test_copy_circuit::( + k, + block.copy_events, + block.circuits_params.max_copy_rows, + ExternalData { + max_txs: block.circuits_params.max_txs, + max_calldata: block.circuits_params.max_calldata, + txs: block.txs, + max_rws: block.circuits_params.max_rws, + rws: block.rws, + bytecodes: block.bytecodes, + }, + ) +} + +fn gen_calldatacopy_data() -> CircuitInputBuilder { + let length = 0x0fffusize; + let code = bytecode! { + PUSH32(Word::from(length)) + PUSH32(Word::from(0x00)) + PUSH32(Word::from(0x00)) + CALLDATACOPY + STOP + }; + let calldata = rand_bytes(length); + let test_ctx = TestContext::<2, 1>::new( + None, + account_0_code_account_1_no_code(code), + |mut txs, accs| { + txs[0] + .from(accs[1].address) + .to(accs[0].address) + .input(calldata.into()); + }, + |block, _txs| block.number(0xcafeu64), + ) + .unwrap(); + let block: GethData = test_ctx.into(); + let mut builder = BlockData::new_from_geth_data_with_params( + block.clone(), + CircuitsParams { + max_rws: 8192, + max_copy_rows: 8192 + 2, + max_calldata: 5000, + ..Default::default() + }, + ) + .new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + builder +} + +fn gen_codecopy_data() -> CircuitInputBuilder { + let code = bytecode! { + PUSH32(Word::from(0x20)) + PUSH32(Word::from(0x00)) + PUSH32(Word::from(0x00)) + CODECOPY + STOP + }; + let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(); + let block: GethData = test_ctx.into(); + let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + builder +} + +fn gen_extcodecopy_data() -> CircuitInputBuilder { + let external_address = MOCK_ACCOUNTS[0]; + let code = bytecode! { + PUSH1(0x30usize) + PUSH1(0x0usize) + PUSH1(0x0usize) + PUSH20(external_address.to_word()) + EXTCODECOPY + STOP + }; + let code_ext = rand_bytes(0x0fffusize); + let test_ctx = TestContext::<3, 1>::new( + None, + |accs| { + accs[0].address(MOCK_ACCOUNTS[1]).code(code.clone()); + + accs[1].address(external_address).code(code_ext.clone()); + + accs[2] + .address(MOCK_ACCOUNTS[2]) + .balance(Word::from(1u64 << 20)); + }, + |mut txs, accs| { + txs[0].to(accs[0].address).from(accs[2].address); + }, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap(); + let block: GethData = test_ctx.into(); + let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + builder +} + +fn gen_sha3_data() -> CircuitInputBuilder { + let (code, _) = gen_sha3_code(0x20, 0x200, MemoryKind::EqualToSize); + let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(); + let block: GethData = test_ctx.into(); + let mut builder = BlockData::new_from_geth_data_with_params( + block.clone(), + CircuitsParams { + max_rws: 2000, + max_copy_rows: 0x200 * 2 + 2, + ..Default::default() + }, + ) + .new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + builder +} + +fn gen_tx_log_data() -> CircuitInputBuilder { + let code = bytecode! { + PUSH32(200) // value + PUSH32(0) // offset + MSTORE + PUSH32(Word::MAX) // topic + PUSH1(32) // length + PUSH1(0) // offset + LOG1 + STOP + }; + let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(); + let block: GethData = test_ctx.into(); + let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + builder +} + +#[test] +fn copy_circuit_valid_calldatacopy() { + let builder = gen_calldatacopy_data(); + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + assert_eq!(test_copy_circuit_from_block(14, block), Ok(())); +} + +#[test] +fn copy_circuit_valid_codecopy() { + let builder = gen_codecopy_data(); + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + assert_eq!(test_copy_circuit_from_block(10, block), Ok(())); +} + +#[test] +fn copy_circuit_valid_extcodecopy() { + let builder = gen_extcodecopy_data(); + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + assert_eq!(test_copy_circuit_from_block(14, block), Ok(())); +} + +#[test] +fn copy_circuit_valid_sha3() { + let builder = gen_sha3_data(); + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + assert_eq!(test_copy_circuit_from_block(14, block), Ok(())); +} + +#[test] +fn copy_circuit_valid_tx_log() { + let builder = gen_tx_log_data(); + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + assert_eq!(test_copy_circuit_from_block(10, block), Ok(())); +} + +#[test] +fn copy_circuit_invalid_calldatacopy() { + let mut builder = gen_calldatacopy_data(); + + // modify first byte of first copy event + builder.block.copy_events[0].bytes[0].0 = + builder.block.copy_events[0].bytes[0].0.wrapping_add(1); + + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + + assert_error_matches( + test_copy_circuit_from_block(14, block), + vec!["Memory lookup", "Tx calldata lookup"], + ); +} + +#[test] +fn copy_circuit_invalid_codecopy() { + let mut builder = gen_codecopy_data(); + + // modify first byte of first copy event + builder.block.copy_events[0].bytes[0].0 = + builder.block.copy_events[0].bytes[0].0.wrapping_add(1); + + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + + assert_error_matches( + test_copy_circuit_from_block(10, block), + vec!["Memory lookup", "Bytecode lookup"], + ); +} + +#[test] +fn copy_circuit_invalid_extcodecopy() { + let mut builder = gen_extcodecopy_data(); + + // modify first byte of first copy event + builder.block.copy_events[0].bytes[0].0 = + builder.block.copy_events[0].bytes[0].0.wrapping_add(1); + + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + + assert_error_matches( + test_copy_circuit_from_block(14, block), + vec!["Memory lookup", "Bytecode lookup"], + ); +} + +#[test] +fn copy_circuit_invalid_sha3() { + let mut builder = gen_sha3_data(); + + // modify first byte of first copy event + builder.block.copy_events[0].bytes[0].0 = + builder.block.copy_events[0].bytes[0].0.wrapping_add(1); + + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + + assert_error_matches( + test_copy_circuit_from_block(14, block), + vec!["Memory lookup"], + ); +} + +#[test] +fn copy_circuit_invalid_tx_log() { + let mut builder = gen_tx_log_data(); + + // modify first byte of first copy event + builder.block.copy_events[0].bytes[0].0 = + builder.block.copy_events[0].bytes[0].0.wrapping_add(1); + + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + + assert_error_matches( + test_copy_circuit_from_block(10, block), + vec!["Memory lookup", "TxLog lookup"], + ); +} + +#[test] +fn variadic_size_check() { + let builder = gen_tx_log_data(); + let block1 = block_convert::(&builder.block, &builder.code_db).unwrap(); + + let block: GethData = TestContext::<0, 0>::new(None, |_| {}, |_, _| {}, |b, _| b) + .unwrap() + .into(); + let mut builder = + BlockData::new_from_geth_data_with_params(block.clone(), CircuitsParams::default()) + .new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + let block2 = block_convert::(&builder.block, &builder.code_db).unwrap(); + + let circuit = CopyCircuit::::new(block1.copy_events, block1.circuits_params.max_copy_rows); + let prover1 = MockProver::::run(14, &circuit, vec![]).unwrap(); + + let circuit = CopyCircuit::::new( + block2.copy_events.clone(), + block2.circuits_params.max_copy_rows, + ); + let prover2 = MockProver::::run(14, &circuit, vec![]).unwrap(); + + assert_eq!(prover1.fixed(), prover2.fixed()); + assert_eq!(prover1.permutation(), prover2.permutation()); +} + +fn assert_error_matches(result: Result<(), Vec>, names: Vec<&str>) { + let errors = result.expect_err("result is not an error"); + assert_eq!(errors.len(), names.len(), "{:?}", errors); + for i in 0..names.len() { + match &errors[i] { + VerifyFailure::Lookup { + name: lookup_name, .. + } => { + assert_eq!(lookup_name, &names[i]) + } + VerifyFailure::ConstraintNotSatisfied { .. } => panic!(), + VerifyFailure::CellNotAssigned { .. } => panic!(), + VerifyFailure::ConstraintPoisoned { .. } => panic!(), + VerifyFailure::Permutation { .. } => panic!(), + } + } +} diff --git a/zkevm-circuits/src/copy_circuit/util.rs b/zkevm-circuits/src/copy_circuit/util.rs new file mode 100644 index 0000000000..87d5056949 --- /dev/null +++ b/zkevm-circuits/src/copy_circuit/util.rs @@ -0,0 +1,22 @@ +use crate::evm_circuit::util::rlc; +use bus_mapping::circuit_input_builder::NumberOrHash; +use eth_types::Field; +use halo2_proofs::circuit::Value; + +/// Encode the type `NumberOrHash` into a field element +pub fn number_or_hash_to_field(v: &NumberOrHash, challenge: Value) -> Value { + match v { + NumberOrHash::Number(n) => Value::known(F::from(*n as u64)), + NumberOrHash::Hash(h) => { + // since code hash in the bytecode table is represented in + // the little-endian form, we reverse the big-endian bytes + // of H256. + let le_bytes = { + let mut b = h.to_fixed_bytes(); + b.reverse(); + b + }; + challenge.map(|challenge| rlc::value(&le_bytes, challenge)) + } + } +} diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index ddd4c1a563..19f198486f 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -9,9 +9,13 @@ use halo2_proofs::{ mod execution; pub mod param; pub(crate) mod step; +pub mod table; pub(crate) mod util; -pub mod table; +#[cfg(any(feature = "test", test))] +pub(crate) mod test; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +pub use self::EvmCircuit as TestEvmCircuit; pub use crate::witness; use crate::{ @@ -423,45 +427,6 @@ impl Circuit for EvmCircuit { } } -#[cfg(any(feature = "test", test))] -pub mod test { - use super::*; - use crate::evm_circuit::witness::Block; - - use eth_types::{Field, Word}; - use rand::{ - distributions::uniform::{SampleRange, SampleUniform}, - random, thread_rng, Rng, - }; - - pub(crate) fn rand_range(range: R) -> T - where - T: SampleUniform, - R: SampleRange, - { - thread_rng().gen_range(range) - } - - pub(crate) fn rand_bytes(n: usize) -> Vec { - (0..n).map(|_| random()).collect() - } - - pub(crate) fn rand_bytes_array() -> [u8; N] { - [(); N].map(|_| random()) - } - - pub(crate) fn rand_word() -> Word { - Word::from_big_endian(&rand_bytes_array::<32>()) - } - - impl EvmCircuit { - pub fn get_test_cicuit_from_block(block: Block) -> Self { - let fixed_table_tags = detect_fixed_table_tags(&block); - EvmCircuit::::new_dev(block, fixed_table_tags) - } - } -} - #[cfg(test)] mod evm_circuit_stats { use crate::{ diff --git a/zkevm-circuits/src/evm_circuit/test.rs b/zkevm-circuits/src/evm_circuit/test.rs new file mode 100644 index 0000000000..b282deb3b1 --- /dev/null +++ b/zkevm-circuits/src/evm_circuit/test.rs @@ -0,0 +1,36 @@ +#![allow(unused_imports)] +pub use super::EvmCircuit; +use crate::evm_circuit::{detect_fixed_table_tags, witness::Block}; + +use eth_types::{Field, Word}; +use rand::{ + distributions::uniform::{SampleRange, SampleUniform}, + random, thread_rng, Rng, +}; + +pub(crate) fn rand_range(range: R) -> T +where + T: SampleUniform, + R: SampleRange, +{ + thread_rng().gen_range(range) +} + +pub(crate) fn rand_bytes(n: usize) -> Vec { + (0..n).map(|_| random()).collect() +} + +pub(crate) fn rand_bytes_array() -> [u8; N] { + [(); N].map(|_| random()) +} + +pub(crate) fn rand_word() -> Word { + Word::from_big_endian(&rand_bytes_array::<32>()) +} + +impl EvmCircuit { + pub fn get_test_cicuit_from_block(block: Block) -> Self { + let fixed_table_tags = detect_fixed_table_tags(&block); + EvmCircuit::::new_dev(block, fixed_table_tags) + } +} diff --git a/zkevm-circuits/src/exp_circuit.rs b/zkevm-circuits/src/exp_circuit.rs index 5355f4051b..b050077455 100644 --- a/zkevm-circuits/src/exp_circuit.rs +++ b/zkevm-circuits/src/exp_circuit.rs @@ -1,7 +1,19 @@ //! Exponentiation verification circuit. -use std::{marker::PhantomData, ops::Add}; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +mod dev; +pub(crate) mod param; +#[cfg(any(feature = "test", test))] +mod test; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +pub use dev::ExpCircuit as TestExpCircuit; +use crate::{ + evm_circuit::util::constraint_builder::BaseConstraintBuilder, + table::{ExpTable, LookupTable}, + util::{Challenges, SubCircuit, SubCircuitConfig}, + witness, +}; use bus_mapping::circuit_input_builder::{ExpEvent, ExpStep}; use eth_types::{Field, ToScalar, U256}; use gadgets::{ @@ -13,27 +25,8 @@ use halo2_proofs::{ plonk::{ConstraintSystem, Error, Selector}, poly::Rotation, }; - -use crate::{ - evm_circuit::util::constraint_builder::BaseConstraintBuilder, - table::{ExpTable, LookupTable}, - util::{Challenges, SubCircuit, SubCircuitConfig}, - witness, -}; - -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -use halo2_proofs::{circuit::SimpleFloorPlanner, plonk::Circuit}; - -/// The number of rows assigned for each step in an exponentiation trace. -pub const OFFSET_INCREMENT: usize = 7usize; -/// The number of rows required for the exponentiation table within the circuit -/// for each step. -pub const ROWS_PER_STEP: usize = 4usize; -/// The gate "verify all but the last step" at constraint "`base_limb[i]` is the -/// same across all steps" uses rotation 10 in `exp_table.base_limb` which is -/// enabled with `q_usable`, which in turn is enabled in all steps. This means -/// this circuit requires these extra rows after the last enabled `q_usable`. -const UNUSABLE_EXP_ROWS: usize = 10usize; +use param::*; +use std::{marker::PhantomData, ops::Add}; /// Layout for the Exponentiation circuit. #[derive(Clone, Debug)] @@ -528,185 +521,3 @@ impl SubCircuit for ExpCircuit { config.assign_exp_events(layouter, &self.exp_events, self.max_exp_rows) } } - -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -impl Circuit for ExpCircuit { - type Config = (ExpCircuitConfig, Challenges); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let exp_table = ExpTable::construct(meta); - let challenges = Challenges::construct(meta); - (ExpCircuitConfig::new(meta, exp_table), challenges) - } - - fn synthesize( - &self, - (config, challenges): Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), halo2_proofs::plonk::Error> { - let challenges = challenges.values(&mut layouter); - self.synthesize_sub(&config, &challenges, &mut layouter) - } -} - -#[cfg(any(feature = "test", test))] -/// Dev helpers -pub mod dev { - use super::*; - use eth_types::Field; - use halo2_proofs::dev::MockProver; - - use crate::evm_circuit::witness::Block; - - /// Test exponentiation circuit with the provided block witness - pub fn test_exp_circuit(k: u32, block: Block) { - let circuit = ExpCircuit::::new( - block.exp_events.clone(), - block.circuits_params.max_exp_steps, - ); - let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); - prover.assert_satisfied_par() - } -} - -#[cfg(test)] -mod tests { - use bus_mapping::{ - circuit_input_builder::{CircuitInputBuilder, CircuitsParams}, - evm::OpcodeId, - mock::BlockData, - }; - use eth_types::{bytecode, geth_types::GethData, Bytecode, Word}; - use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; - use mock::TestContext; - - use crate::{ - evm_circuit::witness::block_convert, - exp_circuit::{dev::test_exp_circuit, ExpCircuit}, - }; - - fn gen_code_single(base: Word, exponent: Word) -> Bytecode { - bytecode! { - PUSH32(exponent) - PUSH32(base) - EXP - STOP - } - } - - fn gen_code_multiple(args: Vec<(Word, Word)>) -> Bytecode { - let mut code = Bytecode::default(); - for (base, exponent) in args.into_iter() { - code.push(32, exponent); - code.push(32, base); - code.write_op(OpcodeId::EXP); - } - code.write_op(OpcodeId::STOP); - code - } - - fn gen_data(code: Bytecode) -> CircuitInputBuilder { - let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(); - let block: GethData = test_ctx.into(); - let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); - builder - .handle_block(&block.eth_block, &block.geth_traces) - .unwrap(); - builder - } - - fn test_ok(base: Word, exponent: Word, k: Option) { - let code = gen_code_single(base, exponent); - let builder = gen_data(code); - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - test_exp_circuit(k.unwrap_or(18), block); - } - - fn test_ok_multiple(args: Vec<(Word, Word)>) { - let code = gen_code_multiple(args); - let builder = gen_data(code); - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - test_exp_circuit(20, block); - } - - #[test] - fn exp_circuit_single() { - test_ok(2.into(), 2.into(), None); - test_ok(3.into(), 7.into(), None); - test_ok(5.into(), 11.into(), None); - test_ok(7.into(), 13.into(), None); - test_ok(11.into(), 17.into(), None); - test_ok(13.into(), 23.into(), None); - test_ok(29.into(), 43.into(), None); - test_ok(41.into(), 259.into(), None); - } - - #[test] - fn exp_circuit_big() { - test_ok( - 2.into(), - Word::from_str_radix("0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE", 16).unwrap(), - Some(20), - ); - } - - #[test] - fn exp_circuit_multiple() { - test_ok_multiple(vec![ - (3.into(), 7.into()), - (5.into(), 11.into()), - (7.into(), 13.into()), - (11.into(), 17.into()), - (13.into(), 23.into()), - (29.into(), 43.into()), - (41.into(), 259.into()), - ]); - } - - #[test] - fn variadic_size_check() { - let k = 20; - // Empty - let block: GethData = TestContext::<0, 0>::new(None, |_| {}, |_, _| {}, |b, _| b) - .unwrap() - .into(); - let mut builder = - BlockData::new_from_geth_data_with_params(block.clone(), CircuitsParams::default()) - .new_circuit_input_builder(); - builder - .handle_block(&block.eth_block, &block.geth_traces) - .unwrap(); - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - let circuit = ExpCircuit::::new( - block.exp_events.clone(), - block.circuits_params.max_exp_steps, - ); - let prover1 = MockProver::::run(k, &circuit, vec![]).unwrap(); - - // Non-empty - let code = bytecode! { - PUSH32(8) - PUSH32(10) - EXP - PUSH32(3) - PUSH32(5) - EXP - STOP - }; - let builder = gen_data(code); - let block = block_convert::(&builder.block, &builder.code_db).unwrap(); - let circuit = ExpCircuit::::new( - block.exp_events.clone(), - block.circuits_params.max_exp_steps, - ); - let prover2 = MockProver::::run(k, &circuit, vec![]).unwrap(); - - assert_eq!(prover1.fixed(), prover2.fixed()); - assert_eq!(prover1.permutation(), prover2.permutation()); - } -} diff --git a/zkevm-circuits/src/exp_circuit/dev.rs b/zkevm-circuits/src/exp_circuit/dev.rs new file mode 100644 index 0000000000..45a1831b6d --- /dev/null +++ b/zkevm-circuits/src/exp_circuit/dev.rs @@ -0,0 +1,36 @@ +pub use super::ExpCircuit; + +use crate::{ + exp_circuit::ExpCircuitConfig, + table::ExpTable, + util::{Challenges, SubCircuit, SubCircuitConfig}, +}; +use eth_types::Field; +use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + plonk::{Circuit, ConstraintSystem, Error}, +}; + +impl Circuit for ExpCircuit { + type Config = (ExpCircuitConfig, Challenges); + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let exp_table = ExpTable::construct(meta); + let challenges = Challenges::construct(meta); + (ExpCircuitConfig::new(meta, exp_table), challenges) + } + + fn synthesize( + &self, + (config, challenges): Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let challenges = challenges.values(&mut layouter); + self.synthesize_sub(&config, &challenges, &mut layouter) + } +} diff --git a/zkevm-circuits/src/exp_circuit/param.rs b/zkevm-circuits/src/exp_circuit/param.rs new file mode 100644 index 0000000000..f5c42a14ce --- /dev/null +++ b/zkevm-circuits/src/exp_circuit/param.rs @@ -0,0 +1,10 @@ +/// The number of rows assigned for each step in an exponentiation trace. +pub(crate) const OFFSET_INCREMENT: usize = 7usize; +/// The number of rows required for the exponentiation table within the circuit +/// for each step. +pub(crate) const ROWS_PER_STEP: usize = 4usize; +/// The gate "verify all but the last step" at constraint "`base_limb[i]` is the +/// same across all steps" uses rotation 10 in `exp_table.base_limb` which is +/// enabled with `q_usable`, which in turn is enabled in all steps. This means +/// this circuit requires these extra rows after the last enabled `q_usable`. +pub(crate) const UNUSABLE_EXP_ROWS: usize = 10usize; diff --git a/zkevm-circuits/src/exp_circuit/test.rs b/zkevm-circuits/src/exp_circuit/test.rs new file mode 100644 index 0000000000..ecd032e1e5 --- /dev/null +++ b/zkevm-circuits/src/exp_circuit/test.rs @@ -0,0 +1,145 @@ +#![allow(unused_imports)] +use crate::{ + evm_circuit::witness::{block_convert, Block}, + exp_circuit::ExpCircuit, +}; +use bus_mapping::{ + circuit_input_builder::{CircuitInputBuilder, CircuitsParams}, + evm::OpcodeId, + mock::BlockData, +}; +use eth_types::{bytecode, geth_types::GethData, Bytecode, Field, Word}; +use halo2_proofs::{ + circuit::SimpleFloorPlanner, dev::MockProver, halo2curves::bn256::Fr, plonk::Circuit, +}; +use mock::TestContext; + +/// Test exponentiation circuit with the provided block witness +pub fn test_exp_circuit(k: u32, block: Block) { + let circuit = ExpCircuit::::new( + block.exp_events.clone(), + block.circuits_params.max_exp_steps, + ); + let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); + prover.assert_satisfied_par() +} + +fn gen_code_single(base: Word, exponent: Word) -> Bytecode { + bytecode! { + PUSH32(exponent) + PUSH32(base) + EXP + STOP + } +} + +fn gen_code_multiple(args: Vec<(Word, Word)>) -> Bytecode { + let mut code = Bytecode::default(); + for (base, exponent) in args.into_iter() { + code.push(32, exponent); + code.push(32, base); + code.write_op(OpcodeId::EXP); + } + code.write_op(OpcodeId::STOP); + code +} + +fn gen_data(code: Bytecode) -> CircuitInputBuilder { + let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(); + let block: GethData = test_ctx.into(); + let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + builder +} + +fn test_ok(base: Word, exponent: Word, k: Option) { + let code = gen_code_single(base, exponent); + let builder = gen_data(code); + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + test_exp_circuit(k.unwrap_or(18), block); +} + +fn test_ok_multiple(args: Vec<(Word, Word)>) { + let code = gen_code_multiple(args); + let builder = gen_data(code); + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + test_exp_circuit(20, block); +} + +#[test] +fn exp_circuit_single() { + test_ok(2.into(), 2.into(), None); + test_ok(3.into(), 7.into(), None); + test_ok(5.into(), 11.into(), None); + test_ok(7.into(), 13.into(), None); + test_ok(11.into(), 17.into(), None); + test_ok(13.into(), 23.into(), None); + test_ok(29.into(), 43.into(), None); + test_ok(41.into(), 259.into(), None); +} + +#[test] +fn exp_circuit_big() { + test_ok( + 2.into(), + Word::from_str_radix("0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE", 16).unwrap(), + Some(20), + ); +} + +#[test] +fn exp_circuit_multiple() { + test_ok_multiple(vec![ + (3.into(), 7.into()), + (5.into(), 11.into()), + (7.into(), 13.into()), + (11.into(), 17.into()), + (13.into(), 23.into()), + (29.into(), 43.into()), + (41.into(), 259.into()), + ]); +} + +#[test] +fn variadic_size_check() { + let k = 20; + // Empty + let block: GethData = TestContext::<0, 0>::new(None, |_| {}, |_, _| {}, |b, _| b) + .unwrap() + .into(); + let mut builder = + BlockData::new_from_geth_data_with_params(block.clone(), CircuitsParams::default()) + .new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + let circuit = ExpCircuit::::new( + block.exp_events.clone(), + block.circuits_params.max_exp_steps, + ); + let prover1 = MockProver::::run(k, &circuit, vec![]).unwrap(); + + // Non-empty + let code = bytecode! { + PUSH32(8) + PUSH32(10) + EXP + PUSH32(3) + PUSH32(5) + EXP + STOP + }; + let builder = gen_data(code); + let block = block_convert::(&builder.block, &builder.code_db).unwrap(); + let circuit = ExpCircuit::::new( + block.exp_events.clone(), + block.circuits_params.max_exp_steps, + ); + let prover2 = MockProver::::run(k, &circuit, vec![]).unwrap(); + + assert_eq!(prover1.fixed(), prover2.fixed()); + assert_eq!(prover1.permutation(), prover2.permutation()); +} diff --git a/zkevm-circuits/src/keccak_circuit.rs b/zkevm-circuits/src/keccak_circuit.rs index 7d814bb58b..0fe0f2a6a2 100644 --- a/zkevm-circuits/src/keccak_circuit.rs +++ b/zkevm-circuits/src/keccak_circuit.rs @@ -4,11 +4,16 @@ mod cell_manager; pub mod keccak_packed_multi; mod param; mod table; -#[cfg(test)] -mod test; /// Util mod util; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +mod dev; +#[cfg(any(feature = "test", test))] +mod test; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +pub use dev::KeccakCircuit as TestKeccakCircuit; + use std::marker::PhantomData; pub use KeccakCircuitConfig as KeccakConfig; @@ -28,9 +33,6 @@ use halo2_proofs::{ }; use log::info; -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -use halo2_proofs::{circuit::SimpleFloorPlanner, plonk::Circuit}; - /// KeccakConfig #[derive(Clone, Debug)] pub struct KeccakCircuitConfig { @@ -1005,42 +1007,6 @@ impl SubCircuit for KeccakCircuit { } } -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -impl Circuit for KeccakCircuit { - type Config = (KeccakCircuitConfig, Challenges); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let keccak_table = KeccakTable::construct(meta); - let challenges = Challenges::construct(meta); - - let config = { - let challenges = challenges.exprs(meta); - KeccakCircuitConfig::new( - meta, - KeccakCircuitConfigArgs { - keccak_table, - challenges, - }, - ) - }; - (config, challenges) - } - - fn synthesize( - &self, - (config, challenges): Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let challenges = challenges.values(&mut layouter); - self.synthesize_sub(&config, &challenges, &mut layouter) - } -} - impl KeccakCircuit { /// Creates a new circuit instance pub fn new(num_rows: usize, inputs: Vec>) -> Self { diff --git a/zkevm-circuits/src/keccak_circuit/dev.rs b/zkevm-circuits/src/keccak_circuit/dev.rs new file mode 100644 index 0000000000..44e7ac07a5 --- /dev/null +++ b/zkevm-circuits/src/keccak_circuit/dev.rs @@ -0,0 +1,47 @@ +pub use super::KeccakCircuit; + +use crate::{ + keccak_circuit::{KeccakCircuitConfig, KeccakCircuitConfigArgs}, + table::KeccakTable, + util::{Challenges, SubCircuit, SubCircuitConfig}, +}; +use eth_types::Field; +use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + plonk::{Circuit, ConstraintSystem, Error}, +}; + +impl Circuit for KeccakCircuit { + type Config = (KeccakCircuitConfig, Challenges); + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let keccak_table = KeccakTable::construct(meta); + let challenges = Challenges::construct(meta); + + let config = { + let challenges = challenges.exprs(meta); + KeccakCircuitConfig::new( + meta, + KeccakCircuitConfigArgs { + keccak_table, + challenges, + }, + ) + }; + (config, challenges) + } + + fn synthesize( + &self, + (config, challenges): Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let challenges = challenges.values(&mut layouter); + self.synthesize_sub(&config, &challenges, &mut layouter) + } +} diff --git a/zkevm-circuits/src/keccak_circuit/test.rs b/zkevm-circuits/src/keccak_circuit/test.rs index 70f0213e9d..31eae29303 100644 --- a/zkevm-circuits/src/keccak_circuit/test.rs +++ b/zkevm-circuits/src/keccak_circuit/test.rs @@ -1,6 +1,12 @@ -use crate::keccak_circuit::KeccakCircuit; +#![allow(unused_imports)] +use super::*; use eth_types::Field; -use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; +use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + dev::MockProver, + halo2curves::bn256::Fr, + plonk::{Circuit, ConstraintSystem, Error}, +}; use log::error; use std::iter::zip; diff --git a/zkevm-circuits/src/pi_circuit.rs b/zkevm-circuits/src/pi_circuit.rs index 0fea2abcb2..44ba6e375e 100644 --- a/zkevm-circuits/src/pi_circuit.rs +++ b/zkevm-circuits/src/pi_circuit.rs @@ -1,6 +1,12 @@ //! Public Input Circuit implementation +mod param; -use std::marker::PhantomData; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +mod dev; +#[cfg(any(feature = "test", test))] +mod test; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +pub use dev::PiTestCircuit; use eth_types::{ geth_types::{BlockConstants, Transaction}, @@ -9,6 +15,8 @@ use eth_types::{ }; use halo2_proofs::plonk::{Instance, SecondPhase}; use keccak256::plain::Keccak; +use param::*; +use std::marker::PhantomData; use crate::{ table::{BlockTable, LookupTable, TxFieldTag, TxTable}, @@ -29,12 +37,6 @@ use halo2_proofs::{ #[cfg(any(feature = "test", test, feature = "test-circuits"))] use halo2_proofs::{circuit::SimpleFloorPlanner, plonk::Circuit}; -/// Fixed by the spec -const BLOCK_LEN: usize = 7 + 256; -const EXTRA_LEN: usize = 2; -const ZERO_BYTE_GAS_COST: u64 = 4; -const NONZERO_BYTE_GAS_COST: u64 = 16; - /// Values of the block table (as in the spec) #[derive(Clone, Default, Debug)] pub struct BlockValues { @@ -1442,92 +1444,6 @@ impl SubCircuit for PiCircuit { } } -// We define the PiTestCircuit as a wrapper over PiCircuit extended to take the -// generic const parameters MAX_TXS and MAX_CALLDATA. This is necessary because -// the trait Circuit requires an implementation of `configure` that doesn't take -// any circuit parameters, and the PiCircuit defines gates that use rotations -// that depend on MAX_TXS and MAX_CALLDATA, so these two values are required -// during the configuration. -/// Test Circuit for PiCircuit -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -#[derive(Default, Clone)] -pub struct PiTestCircuit( - pub PiCircuit, -); - -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -impl SubCircuit - for PiTestCircuit -{ - type Config = PiCircuitConfig; - - fn new_from_block(block: &witness::Block) -> Self { - assert_eq!(block.circuits_params.max_txs, MAX_TXS); - assert_eq!(block.circuits_params.max_calldata, MAX_CALLDATA); - - Self(PiCircuit::new_from_block(block)) - } - - fn min_num_rows_block(block: &witness::Block) -> (usize, usize) { - assert_eq!(block.circuits_params.max_txs, MAX_TXS); - assert_eq!(block.circuits_params.max_calldata, MAX_CALLDATA); - - PiCircuit::min_num_rows_block(block) - } - - /// Compute the public inputs for this circuit. - fn instance(&self) -> Vec> { - self.0.instance() - } - - fn synthesize_sub( - &self, - _config: &Self::Config, - _challenges: &Challenges>, - _layouter: &mut impl Layouter, - ) -> Result<(), Error> { - panic!("use PiCircuit for embedding instead"); - } -} - -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -impl Circuit - for PiTestCircuit -{ - type Config = (PiCircuitConfig, Challenges); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let block_table = BlockTable::construct(meta); - let tx_table = TxTable::construct(meta); - ( - PiCircuitConfig::new( - meta, - PiCircuitConfigArgs { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, - block_table, - tx_table, - }, - ), - Challenges::construct(meta), - ) - } - - fn synthesize( - &self, - (config, challenges): Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let challenges = challenges.values(&mut layouter); - self.0.synthesize_sub(&config, &challenges, &mut layouter) - } -} - /// Compute the raw_public_inputs column from the verifier's perspective. fn raw_public_inputs_col( max_txs: usize, @@ -1655,133 +1571,3 @@ pub fn gen_rand_rpi( let rand_rpi = Word::from(keccak.digest().as_slice()) % F::MODULUS; rand_rpi.to_scalar().expect("rand_rpi.to_scalar") } - -#[cfg(test)] -mod pi_circuit_test { - use super::*; - use halo2_proofs::{ - dev::{MockProver, VerifyFailure}, - halo2curves::bn256::Fr, - }; - use mock::{CORRECT_MOCK_TXS, MOCK_CHAIN_ID}; - use pretty_assertions::assert_eq; - use rand::SeedableRng; - use rand_chacha::ChaCha20Rng; - - fn run( - k: u32, - public_data: PublicData, - ) -> Result<(), Vec> { - let mut rng = ChaCha20Rng::seed_from_u64(2); - let randomness = F::random(&mut rng); - let rand_rpi = F::random(&mut rng); - let mut public_data = public_data; - public_data.chain_id = *MOCK_CHAIN_ID; - - let circuit = PiTestCircuit::(PiCircuit::new( - MAX_TXS, - MAX_CALLDATA, - randomness, - rand_rpi, - public_data, - )); - let public_inputs = circuit.0.instance(); - - let prover = match MockProver::run(k, &circuit, public_inputs) { - Ok(prover) => prover, - Err(e) => panic!("{:#?}", e), - }; - prover.verify() - } - - #[test] - fn test_default_pi() { - const MAX_TXS: usize = 2; - const MAX_CALLDATA: usize = 8; - let public_data = PublicData::default(); - - let k = 17; - assert_eq!(run::(k, public_data), Ok(())); - } - - #[test] - fn test_simple_pi() { - const MAX_TXS: usize = 8; - const MAX_CALLDATA: usize = 200; - - let mut public_data = PublicData::default(); - - let n_tx = 4; - for i in 0..n_tx { - public_data - .transactions - .push(CORRECT_MOCK_TXS[i].clone().into()); - } - - let k = 17; - assert_eq!(run::(k, public_data), Ok(())); - } - - fn run_size_check( - public_data: [PublicData; 2], - ) { - let mut rng = ChaCha20Rng::seed_from_u64(2); - let randomness = F::random(&mut rng); - let rand_rpi = F::random(&mut rng); - - let circuit = PiTestCircuit::(PiCircuit::new( - MAX_TXS, - MAX_CALLDATA, - randomness, - rand_rpi, - public_data[0].clone(), - )); - let public_inputs = circuit.0.instance(); - let prover1 = MockProver::run(20, &circuit, public_inputs).unwrap(); - - let circuit2 = PiTestCircuit::(PiCircuit::new( - MAX_TXS, - MAX_CALLDATA, - randomness, - rand_rpi, - public_data[1].clone(), - )); - let public_inputs = circuit2.0.instance(); - let prover2 = MockProver::run(20, &circuit, public_inputs).unwrap(); - - assert_eq!(prover1.fixed(), prover2.fixed()); - assert_eq!(prover1.permutation(), prover2.permutation()); - } - - #[test] - fn variadic_size_check() { - const MAX_TXS: usize = 8; - const MAX_CALLDATA: usize = 200; - - let mut pub_dat_1 = PublicData { - chain_id: *MOCK_CHAIN_ID, - ..Default::default() - }; - - let n_tx = 2; - for i in 0..n_tx { - pub_dat_1 - .transactions - .push(CORRECT_MOCK_TXS[i].clone().into()); - } - - let mut pub_dat_2 = PublicData { - chain_id: *MOCK_CHAIN_ID, - ..Default::default() - }; - - let n_tx = 4; - for i in 0..n_tx { - pub_dat_2 - .transactions - .push(CORRECT_MOCK_TXS[i].clone().into()); - } - - run_size_check::([pub_dat_1, pub_dat_2]); - } -} diff --git a/zkevm-circuits/src/pi_circuit/dev.rs b/zkevm-circuits/src/pi_circuit/dev.rs new file mode 100644 index 0000000000..c901fb9f58 --- /dev/null +++ b/zkevm-circuits/src/pi_circuit/dev.rs @@ -0,0 +1,84 @@ +use super::*; + +// We define the PiTestCircuit as a wrapper over PiCircuit extended to take the +// generic const parameters MAX_TXS and MAX_CALLDATA. This is necessary because +// the trait Circuit requires an implementation of `configure` that doesn't take +// any circuit parameters, and the PiCircuit defines gates that use rotations +// that depend on MAX_TXS and MAX_CALLDATA, so these two values are required +// during the configuration. +/// Test Circuit for PiCircuit +#[derive(Default, Clone)] +pub struct PiTestCircuit( + pub PiCircuit, +); + +impl SubCircuit + for PiTestCircuit +{ + type Config = PiCircuitConfig; + + fn new_from_block(block: &witness::Block) -> Self { + assert_eq!(block.circuits_params.max_txs, MAX_TXS); + assert_eq!(block.circuits_params.max_calldata, MAX_CALLDATA); + + Self(PiCircuit::new_from_block(block)) + } + + fn min_num_rows_block(block: &witness::Block) -> (usize, usize) { + assert_eq!(block.circuits_params.max_txs, MAX_TXS); + assert_eq!(block.circuits_params.max_calldata, MAX_CALLDATA); + + PiCircuit::min_num_rows_block(block) + } + + /// Compute the public inputs for this circuit. + fn instance(&self) -> Vec> { + self.0.instance() + } + + fn synthesize_sub( + &self, + _config: &Self::Config, + _challenges: &Challenges>, + _layouter: &mut impl Layouter, + ) -> Result<(), Error> { + panic!("use PiCircuit for embedding instead"); + } +} + +impl Circuit + for PiTestCircuit +{ + type Config = (PiCircuitConfig, Challenges); + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let block_table = BlockTable::construct(meta); + let tx_table = TxTable::construct(meta); + ( + PiCircuitConfig::new( + meta, + PiCircuitConfigArgs { + max_txs: MAX_TXS, + max_calldata: MAX_CALLDATA, + block_table, + tx_table, + }, + ), + Challenges::construct(meta), + ) + } + + fn synthesize( + &self, + (config, challenges): Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let challenges = challenges.values(&mut layouter); + self.0.synthesize_sub(&config, &challenges, &mut layouter) + } +} diff --git a/zkevm-circuits/src/pi_circuit/param.rs b/zkevm-circuits/src/pi_circuit/param.rs new file mode 100644 index 0000000000..8c05677fdd --- /dev/null +++ b/zkevm-circuits/src/pi_circuit/param.rs @@ -0,0 +1,5 @@ +/// Fixed by the spec +pub(super) const BLOCK_LEN: usize = 7 + 256; +pub(super) const EXTRA_LEN: usize = 2; +pub(super) const ZERO_BYTE_GAS_COST: u64 = 4; +pub(super) const NONZERO_BYTE_GAS_COST: u64 = 16; diff --git a/zkevm-circuits/src/pi_circuit/test.rs b/zkevm-circuits/src/pi_circuit/test.rs new file mode 100644 index 0000000000..0310d6a0fd --- /dev/null +++ b/zkevm-circuits/src/pi_circuit/test.rs @@ -0,0 +1,126 @@ +#![allow(unused_imports)] +use super::{dev::*, *}; +use halo2_proofs::{ + dev::{MockProver, VerifyFailure}, + halo2curves::bn256::Fr, +}; +use mock::{CORRECT_MOCK_TXS, MOCK_CHAIN_ID}; +use rand::SeedableRng; +use rand_chacha::ChaCha20Rng; + +fn run( + k: u32, + public_data: PublicData, +) -> Result<(), Vec> { + let mut rng = ChaCha20Rng::seed_from_u64(2); + let randomness = F::random(&mut rng); + let rand_rpi = F::random(&mut rng); + let mut public_data = public_data; + public_data.chain_id = *MOCK_CHAIN_ID; + + let circuit = PiTestCircuit::(PiCircuit::new( + MAX_TXS, + MAX_CALLDATA, + randomness, + rand_rpi, + public_data, + )); + let public_inputs = circuit.0.instance(); + + let prover = match MockProver::run(k, &circuit, public_inputs) { + Ok(prover) => prover, + Err(e) => panic!("{:#?}", e), + }; + prover.verify() +} + +#[test] +fn test_default_pi() { + const MAX_TXS: usize = 2; + const MAX_CALLDATA: usize = 8; + let public_data = PublicData::default(); + + let k = 17; + assert_eq!(run::(k, public_data), Ok(())); +} + +#[test] +fn test_simple_pi() { + const MAX_TXS: usize = 8; + const MAX_CALLDATA: usize = 200; + + let mut public_data = PublicData::default(); + + let n_tx = 4; + for i in 0..n_tx { + public_data + .transactions + .push(CORRECT_MOCK_TXS[i].clone().into()); + } + + let k = 17; + assert_eq!(run::(k, public_data), Ok(())); +} + +fn run_size_check( + public_data: [PublicData; 2], +) { + let mut rng = ChaCha20Rng::seed_from_u64(2); + let randomness = F::random(&mut rng); + let rand_rpi = F::random(&mut rng); + + let circuit = PiTestCircuit::(PiCircuit::new( + MAX_TXS, + MAX_CALLDATA, + randomness, + rand_rpi, + public_data[0].clone(), + )); + let public_inputs = circuit.0.instance(); + let prover1 = MockProver::run(20, &circuit, public_inputs).unwrap(); + + let circuit2 = PiTestCircuit::(PiCircuit::new( + MAX_TXS, + MAX_CALLDATA, + randomness, + rand_rpi, + public_data[1].clone(), + )); + let public_inputs = circuit2.0.instance(); + let prover2 = MockProver::run(20, &circuit, public_inputs).unwrap(); + + assert_eq!(prover1.fixed(), prover2.fixed()); + assert_eq!(prover1.permutation(), prover2.permutation()); +} + +#[test] +fn variadic_size_check() { + const MAX_TXS: usize = 8; + const MAX_CALLDATA: usize = 200; + + let mut pub_dat_1 = PublicData { + chain_id: *MOCK_CHAIN_ID, + ..Default::default() + }; + + let n_tx = 2; + for i in 0..n_tx { + pub_dat_1 + .transactions + .push(CORRECT_MOCK_TXS[i].clone().into()); + } + + let mut pub_dat_2 = PublicData { + chain_id: *MOCK_CHAIN_ID, + ..Default::default() + }; + + let n_tx = 4; + for i in 0..n_tx { + pub_dat_2 + .transactions + .push(CORRECT_MOCK_TXS[i].clone().into()); + } + + run_size_check::([pub_dat_1, pub_dat_2]); +} diff --git a/zkevm-circuits/src/root_circuit.rs b/zkevm-circuits/src/root_circuit.rs index 9eb0b35af2..440424fa18 100644 --- a/zkevm-circuits/src/root_circuit.rs +++ b/zkevm-circuits/src/root_circuit.rs @@ -13,6 +13,11 @@ use std::iter; mod aggregation; +#[cfg(any(feature = "test", test))] +mod test; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +pub use self::RootCircuit as TestRootCircuit; + pub use aggregation::{ aggregate, AggregationConfig, EccChip, Halo2Loader, KzgAs, KzgDk, KzgSvk, PlonkSuccinctVerifier, PlonkVerifier, PoseidonTranscript, Snark, SnarkWitness, BITS, LIMBS, @@ -137,90 +142,3 @@ impl<'a, M: MultiMillerLoop> Circuit for RootCircuit<'a, M> { Ok(()) } } - -#[cfg(test)] -mod test { - use crate::{ - root_circuit::{compile, Config, PoseidonTranscript, RootCircuit}, - super_circuit::{super_circuit_tests::block_1tx, SuperCircuit}, - }; - use bus_mapping::circuit_input_builder::CircuitsParams; - use halo2_proofs::{ - circuit::Value, - dev::MockProver, - halo2curves::bn256::Bn256, - plonk::{create_proof, keygen_pk, keygen_vk}, - poly::kzg::{ - commitment::{KZGCommitmentScheme, ParamsKZG}, - multiopen::ProverGWC, - }, - }; - use itertools::Itertools; - use rand::rngs::OsRng; - - #[ignore = "Due to high memory requirement"] - #[test] - fn test_root_circuit() { - let (params, protocol, proof, instance) = { - // Preprocess - const MAX_TXS: usize = 1; - const MAX_CALLDATA: usize = 32; - const TEST_MOCK_RANDOMNESS: u64 = 0x100; - let circuits_params = CircuitsParams { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, - max_rws: 256, - max_copy_rows: 256, - max_exp_steps: 256, - max_bytecode: 512, - max_evm_rows: 0, - max_keccak_rows: 0, - }; - let (k, circuit, instance, _) = - SuperCircuit::<_, MAX_TXS, MAX_CALLDATA, TEST_MOCK_RANDOMNESS>::build( - block_1tx(), - circuits_params, - ) - .unwrap(); - let params = ParamsKZG::::setup(k, OsRng); - let pk = keygen_pk(¶ms, keygen_vk(¶ms, &circuit).unwrap(), &circuit).unwrap(); - let protocol = compile( - ¶ms, - pk.get_vk(), - Config::kzg() - .with_num_instance(instance.iter().map(|instance| instance.len()).collect()), - ); - - // Create proof - let proof = { - let mut transcript = PoseidonTranscript::new(Vec::new()); - create_proof::, ProverGWC<_>, _, _, _, _>( - ¶ms, - &pk, - &[circuit], - &[&instance.iter().map(Vec::as_slice).collect_vec()], - OsRng, - &mut transcript, - ) - .unwrap(); - transcript.finalize() - }; - - (params, protocol, proof, instance) - }; - - let root_circuit = RootCircuit::new( - ¶ms, - &protocol, - Value::known(&instance), - Value::known(&proof), - ) - .unwrap(); - assert_eq!( - MockProver::run(26, &root_circuit, root_circuit.instance()) - .unwrap() - .verify_par(), - Ok(()) - ); - } -} diff --git a/zkevm-circuits/src/root_circuit/test.rs b/zkevm-circuits/src/root_circuit/test.rs new file mode 100644 index 0000000000..36106bc899 --- /dev/null +++ b/zkevm-circuits/src/root_circuit/test.rs @@ -0,0 +1,82 @@ +#![allow(unused_imports)] +pub use super::*; +use crate::super_circuit::{test::block_1tx, SuperCircuit}; +use bus_mapping::circuit_input_builder::CircuitsParams; +use halo2_proofs::{ + circuit::Value, + dev::MockProver, + halo2curves::bn256::Bn256, + plonk::{create_proof, keygen_pk, keygen_vk}, + poly::kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::ProverGWC, + }, +}; +use itertools::Itertools; +use rand::rngs::OsRng; + +#[ignore = "Due to high memory requirement"] +#[test] +fn test_root_circuit() { + let (params, protocol, proof, instance) = { + // Preprocess + const MAX_TXS: usize = 1; + const MAX_CALLDATA: usize = 32; + const TEST_MOCK_RANDOMNESS: u64 = 0x100; + let circuits_params = CircuitsParams { + max_txs: MAX_TXS, + max_calldata: MAX_CALLDATA, + max_rws: 256, + max_copy_rows: 256, + max_exp_steps: 256, + max_bytecode: 512, + max_evm_rows: 0, + max_keccak_rows: 0, + }; + let (k, circuit, instance, _) = + SuperCircuit::<_, MAX_TXS, MAX_CALLDATA, TEST_MOCK_RANDOMNESS>::build( + block_1tx(), + circuits_params, + ) + .unwrap(); + let params = ParamsKZG::::setup(k, OsRng); + let pk = keygen_pk(¶ms, keygen_vk(¶ms, &circuit).unwrap(), &circuit).unwrap(); + let protocol = compile( + ¶ms, + pk.get_vk(), + Config::kzg() + .with_num_instance(instance.iter().map(|instance| instance.len()).collect()), + ); + + // Create proof + let proof = { + let mut transcript = PoseidonTranscript::new(Vec::new()); + create_proof::, ProverGWC<_>, _, _, _, _>( + ¶ms, + &pk, + &[circuit], + &[&instance.iter().map(Vec::as_slice).collect_vec()], + OsRng, + &mut transcript, + ) + .unwrap(); + transcript.finalize() + }; + + (params, protocol, proof, instance) + }; + + let root_circuit = RootCircuit::new( + ¶ms, + &protocol, + Value::known(&instance), + Value::known(&proof), + ) + .unwrap(); + assert_eq!( + MockProver::run(26, &root_circuit, root_circuit.instance()) + .unwrap() + .verify_par(), + Ok(()) + ); +} diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index 749df0750a..acbd8fd908 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -3,10 +3,20 @@ mod constraint_builder; mod lexicographic_ordering; mod lookups; mod multiple_precision_integer; +mod param; mod random_linear_combination; -#[cfg(test)] + +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +mod dev; +#[cfg(any(feature = "test", test))] mod test; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +pub use dev::StateCircuit as TestStateCircuit; +use self::{ + constraint_builder::{MptUpdateTableQueries, RwTableQueries}, + lexicographic_ordering::LimbIndex, +}; use crate::{ evm_circuit::{param::N_BYTES_WORD, util::rlc}, table::{AccountFieldTag, LookupTable, MPTProofType, MptTable, RwTable, RwTableTag}, @@ -29,22 +39,12 @@ use halo2_proofs::{ use lexicographic_ordering::Config as LexicographicOrderingConfig; use lookups::{Chip as LookupsChip, Config as LookupsConfig, Queries as LookupsQueries}; use multiple_precision_integer::{Chip as MpiChip, Config as MpiConfig, Queries as MpiQueries}; +use param::*; use random_linear_combination::{Chip as RlcChip, Config as RlcConfig, Queries as RlcQueries}; -#[cfg(test)] -use std::collections::HashMap; use std::marker::PhantomData; -use self::{ - constraint_builder::{MptUpdateTableQueries, RwTableQueries}, - lexicographic_ordering::LimbIndex, -}; - #[cfg(any(feature = "test", test, feature = "test-circuits"))] -use halo2_proofs::{circuit::SimpleFloorPlanner, plonk::Circuit}; - -const N_LIMBS_RW_COUNTER: usize = 2; -const N_LIMBS_ACCOUNT_ADDRESS: usize = 10; -const N_LIMBS_ID: usize = 2; +use std::collections::HashMap; /// Config for StateCircuit #[derive(Clone)] @@ -427,8 +427,8 @@ pub struct StateCircuit { pub rows: Vec, updates: MptUpdates, pub(crate) n_rows: usize, - #[cfg(test)] - overrides: HashMap<(test::AdviceColumn, isize), F>, + #[cfg(any(feature = "test", test, feature = "test-circuits"))] + overrides: HashMap<(dev::AdviceColumn, isize), F>, _marker: PhantomData, } @@ -441,7 +441,7 @@ impl StateCircuit { rows, updates, n_rows, - #[cfg(test)] + #[cfg(any(feature = "test", test, feature = "test-circuits"))] overrides: HashMap::new(), _marker: PhantomData::default(), } @@ -494,7 +494,7 @@ impl SubCircuit for StateCircuit { self.n_rows, randomness, )?; - #[cfg(test)] + #[cfg(any(feature = "test", test, feature = "test-circuits"))] { let padding_length = RwMap::padding_len(self.rows.len(), self.n_rows); for ((column, row_offset), &f) in &self.overrides { @@ -522,51 +522,6 @@ impl SubCircuit for StateCircuit { } } -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -impl Circuit for StateCircuit -where - F: Field, -{ - type Config = (StateCircuitConfig, Challenges); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let rw_table = RwTable::construct(meta); - let mpt_table = MptTable::construct(meta); - let challenges = Challenges::construct(meta); - - let config = { - let challenges = challenges.exprs(meta); - StateCircuitConfig::new( - meta, - StateCircuitConfigArgs { - rw_table, - mpt_table, - challenges, - }, - ) - }; - - (config, challenges) - } - - fn synthesize( - &self, - (config, challenges): Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let challenges = challenges.values(&mut layouter); - config - .mpt_table - .load(&mut layouter, &self.updates, challenges.evm_word())?; - self.synthesize_sub(&config, &challenges, &mut layouter) - } -} - fn queries(meta: &mut VirtualCells<'_, F>, c: &StateCircuitConfig) -> Queries { let first_different_limb = c.lexicographic_ordering.first_different_limb; let final_bits_sum = meta.query_advice(first_different_limb.bits[3], Rotation::cur()) diff --git a/zkevm-circuits/src/state_circuit/constraint_builder.rs b/zkevm-circuits/src/state_circuit/constraint_builder.rs index 37ac6f32cf..947c6e21c9 100644 --- a/zkevm-circuits/src/state_circuit/constraint_builder.rs +++ b/zkevm-circuits/src/state_circuit/constraint_builder.rs @@ -1,7 +1,6 @@ use super::{ lookups::Queries as LookupsQueries, multiple_precision_integer::Queries as MpiQueries, - random_linear_combination::Queries as RlcQueries, N_LIMBS_ACCOUNT_ADDRESS, N_LIMBS_ID, - N_LIMBS_RW_COUNTER, + param::*, random_linear_combination::Queries as RlcQueries, }; use crate::{ evm_circuit::{ diff --git a/zkevm-circuits/src/state_circuit/dev.rs b/zkevm-circuits/src/state_circuit/dev.rs new file mode 100644 index 0000000000..db8262fcce --- /dev/null +++ b/zkevm-circuits/src/state_circuit/dev.rs @@ -0,0 +1,119 @@ +pub use super::StateCircuit; + +use crate::{ + state_circuit::{StateCircuitConfig, StateCircuitConfigArgs}, + table::{MptTable, RwTable}, + util::{Challenges, SubCircuit, SubCircuitConfig}, +}; +use eth_types::Field; +use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error}, +}; + +impl Circuit for StateCircuit +where + F: Field, +{ + type Config = (StateCircuitConfig, Challenges); + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let rw_table = RwTable::construct(meta); + let mpt_table = MptTable::construct(meta); + let challenges = Challenges::construct(meta); + + let config = { + let challenges = challenges.exprs(meta); + StateCircuitConfig::new( + meta, + StateCircuitConfigArgs { + rw_table, + mpt_table, + challenges, + }, + ) + }; + + (config, challenges) + } + + fn synthesize( + &self, + (config, challenges): Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let challenges = challenges.values(&mut layouter); + config + .mpt_table + .load(&mut layouter, &self.updates, challenges.evm_word())?; + self.synthesize_sub(&config, &challenges, &mut layouter) + } +} + +#[derive(Hash, Eq, PartialEq, Clone, Debug)] +pub enum AdviceColumn { + IsWrite, + Address, + AddressLimb0, + AddressLimb1, + StorageKey, + StorageKeyByte0, + StorageKeyByte1, + Value, + ValuePrev, + RwCounter, + RwCounterLimb0, + RwCounterLimb1, + Tag, + TagBit0, + TagBit1, + TagBit2, + TagBit3, + LimbIndexBit0, // most significant bit + LimbIndexBit1, + LimbIndexBit2, + LimbIndexBit3, + LimbIndexBit4, // least significant bit + InitialValue, + IsZero, // committed_value and value are 0 + // NonEmptyWitness is the BatchedIsZero chip witness that contains the + // inverse of the non-zero value if any in [committed_value, value] + NonEmptyWitness, +} + +impl AdviceColumn { + pub fn value(&self, config: &StateCircuitConfig) -> Column { + match self { + Self::IsWrite => config.rw_table.is_write, + Self::Address => config.rw_table.address, + Self::AddressLimb0 => config.sort_keys.address.limbs[0], + Self::AddressLimb1 => config.sort_keys.address.limbs[1], + Self::StorageKey => config.rw_table.storage_key, + Self::StorageKeyByte0 => config.sort_keys.storage_key.bytes[0], + Self::StorageKeyByte1 => config.sort_keys.storage_key.bytes[1], + Self::Value => config.rw_table.value, + Self::ValuePrev => config.rw_table.value_prev, + Self::RwCounter => config.rw_table.rw_counter, + Self::RwCounterLimb0 => config.sort_keys.rw_counter.limbs[0], + Self::RwCounterLimb1 => config.sort_keys.rw_counter.limbs[1], + Self::Tag => config.rw_table.tag, + Self::TagBit0 => config.sort_keys.tag.bits[0], + Self::TagBit1 => config.sort_keys.tag.bits[1], + Self::TagBit2 => config.sort_keys.tag.bits[2], + Self::TagBit3 => config.sort_keys.tag.bits[3], + Self::LimbIndexBit0 => config.lexicographic_ordering.first_different_limb.bits[0], + Self::LimbIndexBit1 => config.lexicographic_ordering.first_different_limb.bits[1], + Self::LimbIndexBit2 => config.lexicographic_ordering.first_different_limb.bits[2], + Self::LimbIndexBit3 => config.lexicographic_ordering.first_different_limb.bits[3], + Self::LimbIndexBit4 => config.lexicographic_ordering.first_different_limb.bits[4], + Self::InitialValue => config.initial_value, + Self::IsZero => config.is_non_exist.is_zero, + Self::NonEmptyWitness => config.is_non_exist.nonempty_witness, + } + } +} diff --git a/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs b/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs index cb84cab754..e43c9b07d0 100644 --- a/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs +++ b/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs @@ -1,4 +1,4 @@ -use super::{lookups, SortKeysConfig, N_LIMBS_ACCOUNT_ADDRESS, N_LIMBS_ID, N_LIMBS_RW_COUNTER}; +use super::{lookups, param::*, SortKeysConfig}; use crate::{evm_circuit::param::N_BYTES_WORD, impl_expr, util::Expr, witness::Rw}; use eth_types::{Field, ToBigEndian}; use gadgets::binary_number::{AsBits, BinaryNumberChip, BinaryNumberConfig}; diff --git a/zkevm-circuits/src/state_circuit/multiple_precision_integer.rs b/zkevm-circuits/src/state_circuit/multiple_precision_integer.rs index fcd71f1bdf..2a8d963baa 100644 --- a/zkevm-circuits/src/state_circuit/multiple_precision_integer.rs +++ b/zkevm-circuits/src/state_circuit/multiple_precision_integer.rs @@ -1,4 +1,4 @@ -use super::{lookups, N_LIMBS_ACCOUNT_ADDRESS, N_LIMBS_RW_COUNTER}; +use super::{lookups, param::*}; use crate::util::Expr; use eth_types::{Address, Field}; use halo2_proofs::{ diff --git a/zkevm-circuits/src/state_circuit/param.rs b/zkevm-circuits/src/state_circuit/param.rs new file mode 100644 index 0000000000..fb30860c12 --- /dev/null +++ b/zkevm-circuits/src/state_circuit/param.rs @@ -0,0 +1,3 @@ +pub(super) const N_LIMBS_RW_COUNTER: usize = 2; +pub(super) const N_LIMBS_ACCOUNT_ADDRESS: usize = 10; +pub(super) const N_LIMBS_ID: usize = 2; diff --git a/zkevm-circuits/src/state_circuit/test.rs b/zkevm-circuits/src/state_circuit/test.rs index a8e273fcf6..55bc7acfec 100644 --- a/zkevm-circuits/src/state_circuit/test.rs +++ b/zkevm-circuits/src/state_circuit/test.rs @@ -1,4 +1,5 @@ -use super::{StateCircuit, StateCircuitConfig}; +#![allow(unused_imports)] +pub use super::{dev::*, *}; use crate::{ table::{AccountFieldTag, CallContextFieldTag, RwTableTag, TxLogFieldTag, TxReceiptFieldTag}, util::SubCircuit, @@ -15,6 +16,7 @@ use eth_types::{ use gadgets::binary_number::AsBits; use halo2_proofs::{ arithmetic::Field as Halo2Field, + circuit::SimpleFloorPlanner, dev::{MockProver, VerifyFailure}, halo2curves::bn256::{Bn256, Fr}, plonk::{keygen_vk, Advice, Circuit, Column, ConstraintSystem}, @@ -26,69 +28,6 @@ use strum::IntoEnumIterator; const N_ROWS: usize = 1 << 16; -#[derive(Hash, Eq, PartialEq, Clone, Debug)] -pub enum AdviceColumn { - IsWrite, - Address, - AddressLimb0, - AddressLimb1, - StorageKey, - StorageKeyByte0, - StorageKeyByte1, - Value, - ValuePrev, - RwCounter, - RwCounterLimb0, - RwCounterLimb1, - Tag, - TagBit0, - TagBit1, - TagBit2, - TagBit3, - LimbIndexBit0, // most significant bit - LimbIndexBit1, - LimbIndexBit2, - LimbIndexBit3, - LimbIndexBit4, // least significant bit - InitialValue, - IsZero, // committed_value and value are 0 - // NonEmptyWitness is the BatchedIsZero chip witness that contains the - // inverse of the non-zero value if any in [committed_value, value] - NonEmptyWitness, -} - -impl AdviceColumn { - pub fn value(&self, config: &StateCircuitConfig) -> Column { - match self { - Self::IsWrite => config.rw_table.is_write, - Self::Address => config.rw_table.address, - Self::AddressLimb0 => config.sort_keys.address.limbs[0], - Self::AddressLimb1 => config.sort_keys.address.limbs[1], - Self::StorageKey => config.rw_table.storage_key, - Self::StorageKeyByte0 => config.sort_keys.storage_key.bytes[0], - Self::StorageKeyByte1 => config.sort_keys.storage_key.bytes[1], - Self::Value => config.rw_table.value, - Self::ValuePrev => config.rw_table.value_prev, - Self::RwCounter => config.rw_table.rw_counter, - Self::RwCounterLimb0 => config.sort_keys.rw_counter.limbs[0], - Self::RwCounterLimb1 => config.sort_keys.rw_counter.limbs[1], - Self::Tag => config.rw_table.tag, - Self::TagBit0 => config.sort_keys.tag.bits[0], - Self::TagBit1 => config.sort_keys.tag.bits[1], - Self::TagBit2 => config.sort_keys.tag.bits[2], - Self::TagBit3 => config.sort_keys.tag.bits[3], - Self::LimbIndexBit0 => config.lexicographic_ordering.first_different_limb.bits[0], - Self::LimbIndexBit1 => config.lexicographic_ordering.first_different_limb.bits[1], - Self::LimbIndexBit2 => config.lexicographic_ordering.first_different_limb.bits[2], - Self::LimbIndexBit3 => config.lexicographic_ordering.first_different_limb.bits[3], - Self::LimbIndexBit4 => config.lexicographic_ordering.first_different_limb.bits[4], - Self::InitialValue => config.initial_value, - Self::IsZero => config.is_non_exist.is_zero, - Self::NonEmptyWitness => config.is_non_exist.nonempty_witness, - } - } -} - fn test_state_circuit_ok( memory_ops: Vec>, stack_ops: Vec>, diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 64060c11a7..9f4e55ebd3 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -50,6 +50,9 @@ //! - [x] Tx Circuit //! - [ ] MPT Circuit +#[cfg(any(feature = "test", test))] +pub(crate) mod test; + use crate::{ bytecode_circuit::circuit::{ BytecodeCircuit, BytecodeCircuitConfig, BytecodeCircuitConfigArgs, @@ -450,193 +453,3 @@ impl::default(); - SuperCircuit::<_, 1, 32, 0x100>::configure(&mut cs); - log::info!("super circuit degree: {}", cs.degree()); - log::info!("super circuit minimum_rows: {}", cs.minimum_rows()); - assert!(cs.degree() <= 9); - } - - fn test_super_circuit< - const MAX_TXS: usize, - const MAX_CALLDATA: usize, - const MOCK_RANDOMNESS: u64, - >( - block: GethData, - circuits_params: CircuitsParams, - ) { - let (k, circuit, instance, _) = - SuperCircuit::::build( - block, - circuits_params, - ) - .unwrap(); - let prover = MockProver::run(k, &circuit, instance).unwrap(); - let res = prover.verify_par(); - if let Err(err) = res { - error!("Verification failures: {:#?}", err); - panic!("Failed verification"); - } - } - - pub(crate) fn block_1tx() -> GethData { - let mut rng = ChaCha20Rng::seed_from_u64(2); - - let chain_id = (*MOCK_CHAIN_ID).as_u64(); - - let bytecode = bytecode! { - GAS - STOP - }; - - let wallet_a = LocalWallet::new(&mut rng).with_chain_id(chain_id); - - let addr_a = wallet_a.address(); - let addr_b = address!("0x000000000000000000000000000000000000BBBB"); - - let mut wallets = HashMap::new(); - wallets.insert(wallet_a.address(), wallet_a); - - let mut block: GethData = TestContext::<2, 1>::new( - None, - |accs| { - accs[0] - .address(addr_b) - .balance(Word::from(1u64 << 20)) - .code(bytecode); - accs[1].address(addr_a).balance(Word::from(1u64 << 20)); - }, - |mut txs, accs| { - txs[0] - .from(accs[1].address) - .to(accs[0].address) - .gas(Word::from(1_000_000u64)); - }, - |block, _tx| block.number(0xcafeu64), - ) - .unwrap() - .into(); - block.sign(&wallets); - block - } - - fn block_2tx() -> GethData { - let mut rng = ChaCha20Rng::seed_from_u64(2); - - let chain_id = (*MOCK_CHAIN_ID).as_u64(); - - let bytecode = bytecode! { - GAS - STOP - }; - - let wallet_a = LocalWallet::new(&mut rng).with_chain_id(chain_id); - - let addr_a = wallet_a.address(); - let addr_b = address!("0x000000000000000000000000000000000000BBBB"); - - let mut wallets = HashMap::new(); - wallets.insert(wallet_a.address(), wallet_a); - - let mut block: GethData = TestContext::<2, 2>::new( - None, - |accs| { - accs[0] - .address(addr_b) - .balance(Word::from(1u64 << 20)) - .code(bytecode); - accs[1].address(addr_a).balance(Word::from(1u64 << 20)); - }, - |mut txs, accs| { - txs[0] - .from(accs[1].address) - .to(accs[0].address) - .gas(Word::from(1_000_000u64)); - txs[1] - .from(accs[1].address) - .to(accs[0].address) - .gas(Word::from(1_000_000u64)); - }, - |block, _tx| block.number(0xcafeu64), - ) - .unwrap() - .into(); - block.sign(&wallets); - block - } - - const TEST_MOCK_RANDOMNESS: u64 = 0x100; - - // High memory usage test. Run in serial with: - // `cargo test [...] serial_ -- --ignored --test-threads 1` - #[ignore] - #[test] - fn serial_test_super_circuit_1tx_1max_tx() { - let block = block_1tx(); - const MAX_TXS: usize = 1; - const MAX_CALLDATA: usize = 32; - let circuits_params = CircuitsParams { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, - max_rws: 256, - max_copy_rows: 256, - max_exp_steps: 256, - max_bytecode: 512, - max_evm_rows: 0, - max_keccak_rows: 0, - }; - test_super_circuit::(block, circuits_params); - } - #[ignore] - #[test] - fn serial_test_super_circuit_1tx_2max_tx() { - let block = block_1tx(); - const MAX_TXS: usize = 2; - const MAX_CALLDATA: usize = 32; - let circuits_params = CircuitsParams { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, - max_rws: 256, - max_copy_rows: 256, - max_exp_steps: 256, - max_bytecode: 512, - max_evm_rows: 0, - max_keccak_rows: 0, - }; - test_super_circuit::(block, circuits_params); - } - #[ignore] - #[test] - fn serial_test_super_circuit_2tx_2max_tx() { - let block = block_2tx(); - const MAX_TXS: usize = 2; - const MAX_CALLDATA: usize = 32; - let circuits_params = CircuitsParams { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, - max_rws: 256, - max_copy_rows: 256, - max_exp_steps: 256, - max_bytecode: 512, - max_evm_rows: 0, - max_keccak_rows: 0, - }; - test_super_circuit::(block, circuits_params); - } -} diff --git a/zkevm-circuits/src/super_circuit/test.rs b/zkevm-circuits/src/super_circuit/test.rs new file mode 100644 index 0000000000..989d143958 --- /dev/null +++ b/zkevm-circuits/src/super_circuit/test.rs @@ -0,0 +1,183 @@ +pub use super::*; +use ethers_signers::{LocalWallet, Signer}; +use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; +use log::error; +use mock::{TestContext, MOCK_CHAIN_ID}; +use rand::SeedableRng; +use rand_chacha::ChaCha20Rng; +use std::collections::HashMap; + +use eth_types::{address, bytecode, geth_types::GethData, Word}; + +#[test] +fn super_circuit_degree() { + let mut cs = ConstraintSystem::::default(); + SuperCircuit::<_, 1, 32, 0x100>::configure(&mut cs); + log::info!("super circuit degree: {}", cs.degree()); + log::info!("super circuit minimum_rows: {}", cs.minimum_rows()); + assert!(cs.degree() <= 9); +} + +fn test_super_circuit< + const MAX_TXS: usize, + const MAX_CALLDATA: usize, + const MOCK_RANDOMNESS: u64, +>( + block: GethData, + circuits_params: CircuitsParams, +) { + let (k, circuit, instance, _) = + SuperCircuit::::build(block, circuits_params) + .unwrap(); + let prover = MockProver::run(k, &circuit, instance).unwrap(); + let res = prover.verify_par(); + if let Err(err) = res { + error!("Verification failures: {:#?}", err); + panic!("Failed verification"); + } +} + +pub(crate) fn block_1tx() -> GethData { + let mut rng = ChaCha20Rng::seed_from_u64(2); + + let chain_id = (*MOCK_CHAIN_ID).as_u64(); + + let bytecode = bytecode! { + GAS + STOP + }; + + let wallet_a = LocalWallet::new(&mut rng).with_chain_id(chain_id); + + let addr_a = wallet_a.address(); + let addr_b = address!("0x000000000000000000000000000000000000BBBB"); + + let mut wallets = HashMap::new(); + wallets.insert(wallet_a.address(), wallet_a); + + let mut block: GethData = TestContext::<2, 1>::new( + None, + |accs| { + accs[0] + .address(addr_b) + .balance(Word::from(1u64 << 20)) + .code(bytecode); + accs[1].address(addr_a).balance(Word::from(1u64 << 20)); + }, + |mut txs, accs| { + txs[0] + .from(accs[1].address) + .to(accs[0].address) + .gas(Word::from(1_000_000u64)); + }, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap() + .into(); + block.sign(&wallets); + block +} + +fn block_2tx() -> GethData { + let mut rng = ChaCha20Rng::seed_from_u64(2); + + let chain_id = (*MOCK_CHAIN_ID).as_u64(); + + let bytecode = bytecode! { + GAS + STOP + }; + + let wallet_a = LocalWallet::new(&mut rng).with_chain_id(chain_id); + + let addr_a = wallet_a.address(); + let addr_b = address!("0x000000000000000000000000000000000000BBBB"); + + let mut wallets = HashMap::new(); + wallets.insert(wallet_a.address(), wallet_a); + + let mut block: GethData = TestContext::<2, 2>::new( + None, + |accs| { + accs[0] + .address(addr_b) + .balance(Word::from(1u64 << 20)) + .code(bytecode); + accs[1].address(addr_a).balance(Word::from(1u64 << 20)); + }, + |mut txs, accs| { + txs[0] + .from(accs[1].address) + .to(accs[0].address) + .gas(Word::from(1_000_000u64)); + txs[1] + .from(accs[1].address) + .to(accs[0].address) + .gas(Word::from(1_000_000u64)); + }, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap() + .into(); + block.sign(&wallets); + block +} + +const TEST_MOCK_RANDOMNESS: u64 = 0x100; + +// High memory usage test. Run in serial with: +// `cargo test [...] serial_ -- --ignored --test-threads 1` +#[ignore] +#[test] +fn serial_test_super_circuit_1tx_1max_tx() { + let block = block_1tx(); + const MAX_TXS: usize = 1; + const MAX_CALLDATA: usize = 32; + let circuits_params = CircuitsParams { + max_txs: MAX_TXS, + max_calldata: MAX_CALLDATA, + max_rws: 256, + max_copy_rows: 256, + max_exp_steps: 256, + max_bytecode: 512, + max_evm_rows: 0, + max_keccak_rows: 0, + }; + test_super_circuit::(block, circuits_params); +} +#[ignore] +#[test] +fn serial_test_super_circuit_1tx_2max_tx() { + let block = block_1tx(); + const MAX_TXS: usize = 2; + const MAX_CALLDATA: usize = 32; + let circuits_params = CircuitsParams { + max_txs: MAX_TXS, + max_calldata: MAX_CALLDATA, + max_rws: 256, + max_copy_rows: 256, + max_exp_steps: 256, + max_bytecode: 512, + max_evm_rows: 0, + max_keccak_rows: 0, + }; + test_super_circuit::(block, circuits_params); +} +#[ignore] +#[test] +fn serial_test_super_circuit_2tx_2max_tx() { + let block = block_2tx(); + const MAX_TXS: usize = 2; + const MAX_CALLDATA: usize = 32; + let circuits_params = CircuitsParams { + max_txs: MAX_TXS, + max_calldata: MAX_CALLDATA, + max_rws: 256, + max_copy_rows: 256, + max_exp_steps: 256, + max_bytecode: 512, + max_evm_rows: 0, + max_keccak_rows: 0, + }; + test_super_circuit::(block, circuits_params); +} diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 7c4b2f36a6..c1eddcbb83 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -1,9 +1,9 @@ //! Table definitions used cross-circuits use crate::{ - copy_circuit::number_or_hash_to_field, + copy_circuit::util::number_or_hash_to_field, evm_circuit::util::rlc, - exp_circuit::{OFFSET_INCREMENT, ROWS_PER_STEP}, + exp_circuit::param::{OFFSET_INCREMENT, ROWS_PER_STEP}, impl_expr, util::{build_tx_log_address, Challenges}, witness::{ diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index ab1d09f55e..d49db63e21 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -6,6 +6,13 @@ pub mod sign_verify; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +mod dev; +#[cfg(any(feature = "test", test))] +mod test; +#[cfg(any(feature = "test", test, feature = "test-circuits"))] +pub use dev::TxCircuit as TestTxCircuit; + use crate::{ table::{KeccakTable, TxFieldTag, TxTable}, util::{random_linear_combine_word as rlc, Challenges, SubCircuit, SubCircuitConfig}, @@ -23,20 +30,6 @@ use log::error; use sign_verify::{AssignedSignatureVerify, SignVerifyChip, SignVerifyConfig}; use std::marker::PhantomData; -pub use halo2_proofs::halo2curves::{ - group::{ - ff::{Field as GroupField, PrimeField}, - prime::PrimeCurveAffine, - Curve, Group, GroupEncoding, - }, - secp256k1::{self, Secp256k1Affine, Secp256k1Compressed}, -}; - -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -use bus_mapping::circuit_input_builder::keccak_inputs_tx_circuit; -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -use halo2_proofs::{circuit::SimpleFloorPlanner, plonk::Circuit}; - /// Number of static fields per tx: [nonce, gas, gas_price, /// caller_address, callee_address, is_create, value, call_data_length, /// call_data_gas_cost, tx_sign_hash]. @@ -386,163 +379,3 @@ impl SubCircuit for TxCircuit { vec![vec![]] } } - -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -impl Circuit for TxCircuit { - type Config = (TxCircuitConfig, Challenges); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let tx_table = TxTable::construct(meta); - let keccak_table = KeccakTable::construct(meta); - let challenges = Challenges::construct(meta); - - let config = { - let challenges = challenges.exprs(meta); - TxCircuitConfig::new( - meta, - TxCircuitConfigArgs { - tx_table, - keccak_table, - challenges, - }, - ) - }; - - (config, challenges) - } - - fn synthesize( - &self, - (config, challenges): Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let challenges = challenges.values(&mut layouter); - - config.keccak_table.dev_load( - &mut layouter, - &keccak_inputs_tx_circuit(&self.txs[..], self.chain_id).map_err(|e| { - error!("keccak_inputs_tx_circuit error: {:?}", e); - Error::Synthesis - })?, - &challenges, - )?; - self.synthesize_sub(&config, &challenges, &mut layouter) - } -} - -#[cfg(test)] -mod tx_circuit_tests { - use super::*; - use crate::util::log2_ceil; - use eth_types::address; - use halo2_proofs::{ - dev::{MockProver, VerifyFailure}, - halo2curves::bn256::Fr, - }; - use mock::AddrOrWallet; - use pretty_assertions::assert_eq; - - const NUM_BLINDING_ROWS: usize = 64; - - fn run( - txs: Vec, - chain_id: u64, - max_txs: usize, - max_calldata: usize, - ) -> Result<(), Vec> { - let k = log2_ceil(NUM_BLINDING_ROWS + TxCircuit::::min_num_rows(max_txs, max_calldata)); - // SignVerifyChip -> ECDSAChip -> MainGate instance column - let circuit = TxCircuit::::new(max_txs, max_calldata, chain_id, txs); - - let prover = match MockProver::run(k, &circuit, vec![vec![]]) { - Ok(prover) => prover, - Err(e) => panic!("{:#?}", e), - }; - prover.verify() - } - - #[test] - fn tx_circuit_2tx_2max_tx() { - const NUM_TXS: usize = 2; - const MAX_TXS: usize = 2; - const MAX_CALLDATA: usize = 32; - - assert_eq!( - run::( - mock::CORRECT_MOCK_TXS[..NUM_TXS] - .iter() - .map(|tx| Transaction::from(tx.clone())) - .collect_vec(), - mock::MOCK_CHAIN_ID.as_u64(), - MAX_TXS, - MAX_CALLDATA - ), - Ok(()) - ); - } - - #[test] - fn tx_circuit_1tx_1max_tx() { - const MAX_TXS: usize = 1; - const MAX_CALLDATA: usize = 32; - - let chain_id: u64 = mock::MOCK_CHAIN_ID.as_u64(); - - let tx: Transaction = mock::CORRECT_MOCK_TXS[0].clone().into(); - - assert_eq!(run::(vec![tx], chain_id, MAX_TXS, MAX_CALLDATA), Ok(())); - } - - #[test] - fn tx_circuit_1tx_2max_tx() { - const MAX_TXS: usize = 2; - const MAX_CALLDATA: usize = 32; - - let chain_id: u64 = mock::MOCK_CHAIN_ID.as_u64(); - - let tx: Transaction = mock::CORRECT_MOCK_TXS[0].clone().into(); - - assert_eq!(run::(vec![tx], chain_id, MAX_TXS, MAX_CALLDATA), Ok(())); - } - - #[test] - fn tx_circuit_bad_address() { - const MAX_TXS: usize = 1; - const MAX_CALLDATA: usize = 32; - - let mut tx = mock::CORRECT_MOCK_TXS[0].clone(); - // This address doesn't correspond to the account that signed this tx. - tx.from = AddrOrWallet::from(address!("0x1230000000000000000000000000000000000456")); - - assert!(run::( - vec![tx.into()], - mock::MOCK_CHAIN_ID.as_u64(), - MAX_TXS, - MAX_CALLDATA - ) - .is_err(),); - } - - #[test] - fn variadic_size_check() { - const MAX_TXS: usize = 2; - const MAX_CALLDATA: usize = 32; - - let chain_id: u64 = mock::MOCK_CHAIN_ID.as_u64(); - let tx1: Transaction = mock::CORRECT_MOCK_TXS[0].clone().into(); - let tx2: Transaction = mock::CORRECT_MOCK_TXS[1].clone().into(); - let circuit = TxCircuit::::new(MAX_TXS, MAX_CALLDATA, chain_id, vec![tx1.clone()]); - let prover1 = MockProver::::run(20, &circuit, vec![vec![]]).unwrap(); - - let circuit = TxCircuit::::new(MAX_TXS, MAX_CALLDATA, chain_id, vec![tx1, tx2]); - let prover2 = MockProver::::run(20, &circuit, vec![vec![]]).unwrap(); - - assert_eq!(prover1.fixed(), prover2.fixed()); - assert_eq!(prover1.permutation(), prover2.permutation()); - } -} diff --git a/zkevm-circuits/src/tx_circuit/dev.rs b/zkevm-circuits/src/tx_circuit/dev.rs new file mode 100644 index 0000000000..5ddeb02c34 --- /dev/null +++ b/zkevm-circuits/src/tx_circuit/dev.rs @@ -0,0 +1,61 @@ +pub use super::TxCircuit; + +use crate::{ + table::{KeccakTable, TxTable}, + tx_circuit::{TxCircuitConfig, TxCircuitConfigArgs}, + util::{Challenges, SubCircuit, SubCircuitConfig}, +}; +use bus_mapping::circuit_input_builder::keccak_inputs_tx_circuit; +use eth_types::Field; +use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner}, + plonk::{Circuit, ConstraintSystem, Error}, +}; +use log::error; + +impl Circuit for TxCircuit { + type Config = (TxCircuitConfig, Challenges); + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let tx_table = TxTable::construct(meta); + let keccak_table = KeccakTable::construct(meta); + let challenges = Challenges::construct(meta); + + let config = { + let challenges = challenges.exprs(meta); + TxCircuitConfig::new( + meta, + TxCircuitConfigArgs { + tx_table, + keccak_table, + challenges, + }, + ) + }; + + (config, challenges) + } + + fn synthesize( + &self, + (config, challenges): Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let challenges = challenges.values(&mut layouter); + + config.keccak_table.dev_load( + &mut layouter, + &keccak_inputs_tx_circuit(&self.txs[..], self.chain_id).map_err(|e| { + error!("keccak_inputs_tx_circuit error: {:?}", e); + Error::Synthesis + })?, + &challenges, + )?; + self.synthesize_sub(&config, &challenges, &mut layouter) + } +} diff --git a/zkevm-circuits/src/tx_circuit/test.rs b/zkevm-circuits/src/tx_circuit/test.rs new file mode 100644 index 0000000000..71ed0ce597 --- /dev/null +++ b/zkevm-circuits/src/tx_circuit/test.rs @@ -0,0 +1,108 @@ +#![allow(unused_imports)] +use super::*; +use crate::util::log2_ceil; +use eth_types::address; +use halo2_proofs::{ + dev::{MockProver, VerifyFailure}, + halo2curves::bn256::Fr, +}; +use mock::AddrOrWallet; + +const NUM_BLINDING_ROWS: usize = 64; + +fn run( + txs: Vec, + chain_id: u64, + max_txs: usize, + max_calldata: usize, +) -> Result<(), Vec> { + let k = log2_ceil(NUM_BLINDING_ROWS + TxCircuit::::min_num_rows(max_txs, max_calldata)); + // SignVerifyChip -> ECDSAChip -> MainGate instance column + let circuit = TxCircuit::::new(max_txs, max_calldata, chain_id, txs); + + let prover = match MockProver::run(k, &circuit, vec![vec![]]) { + Ok(prover) => prover, + Err(e) => panic!("{:#?}", e), + }; + prover.verify() +} + +#[test] +fn tx_circuit_2tx_2max_tx() { + const NUM_TXS: usize = 2; + const MAX_TXS: usize = 2; + const MAX_CALLDATA: usize = 32; + + assert_eq!( + run::( + mock::CORRECT_MOCK_TXS[..NUM_TXS] + .iter() + .map(|tx| Transaction::from(tx.clone())) + .collect_vec(), + mock::MOCK_CHAIN_ID.as_u64(), + MAX_TXS, + MAX_CALLDATA + ), + Ok(()) + ); +} + +#[test] +fn tx_circuit_1tx_1max_tx() { + const MAX_TXS: usize = 1; + const MAX_CALLDATA: usize = 32; + + let chain_id: u64 = mock::MOCK_CHAIN_ID.as_u64(); + + let tx: Transaction = mock::CORRECT_MOCK_TXS[0].clone().into(); + + assert_eq!(run::(vec![tx], chain_id, MAX_TXS, MAX_CALLDATA), Ok(())); +} + +#[test] +fn tx_circuit_1tx_2max_tx() { + const MAX_TXS: usize = 2; + const MAX_CALLDATA: usize = 32; + + let chain_id: u64 = mock::MOCK_CHAIN_ID.as_u64(); + + let tx: Transaction = mock::CORRECT_MOCK_TXS[0].clone().into(); + + assert_eq!(run::(vec![tx], chain_id, MAX_TXS, MAX_CALLDATA), Ok(())); +} + +#[test] +fn tx_circuit_bad_address() { + const MAX_TXS: usize = 1; + const MAX_CALLDATA: usize = 32; + + let mut tx = mock::CORRECT_MOCK_TXS[0].clone(); + // This address doesn't correspond to the account that signed this tx. + tx.from = AddrOrWallet::from(address!("0x1230000000000000000000000000000000000456")); + + assert!(run::( + vec![tx.into()], + mock::MOCK_CHAIN_ID.as_u64(), + MAX_TXS, + MAX_CALLDATA + ) + .is_err(),); +} + +#[test] +fn variadic_size_check() { + const MAX_TXS: usize = 2; + const MAX_CALLDATA: usize = 32; + + let chain_id: u64 = mock::MOCK_CHAIN_ID.as_u64(); + let tx1: Transaction = mock::CORRECT_MOCK_TXS[0].clone().into(); + let tx2: Transaction = mock::CORRECT_MOCK_TXS[1].clone().into(); + let circuit = TxCircuit::::new(MAX_TXS, MAX_CALLDATA, chain_id, vec![tx1.clone()]); + let prover1 = MockProver::::run(20, &circuit, vec![vec![]]).unwrap(); + + let circuit = TxCircuit::::new(MAX_TXS, MAX_CALLDATA, chain_id, vec![tx1, tx2]); + let prover2 = MockProver::::run(20, &circuit, vec![vec![]]).unwrap(); + + assert_eq!(prover1.fixed(), prover2.fixed()); + assert_eq!(prover1.permutation(), prover2.permutation()); +} diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index a6a025da60..6c42920dab 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -68,7 +68,7 @@ impl Block { } #[cfg(feature = "test")] -use crate::exp_circuit::OFFSET_INCREMENT; +use crate::exp_circuit::param::OFFSET_INCREMENT; #[cfg(feature = "test")] use crate::util::log2_ceil; From 4e5e78a13c70612eeaf70c19f270f58f7bb4bca9 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 11 Apr 2023 18:03:03 +0800 Subject: [PATCH 003/102] bus-mapping: more robust access parsing (#1311) ### Description When building AccessSet, we read stack input of opcode(eg: read last element of stack when processing BALANCE opcode). But this method will encounter error when dealing with some ill-formed bytecode(BALANCE when empty stack). So in this PR, when access parsing for a single step encounters errors, the error is printed, the access parsing procedure will continue instead of being interrupted and return. ### Issue Link [_link issue here_] ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - [_item_] ### Rationale [_design decisions and extended information_] ### How Has This Been Tested? "StackUnderFlowContractCreation_d0_g0_v0" in testool can pass with this PR
## How to fill a PR description Please give a concise description of your PR. The target readers could be future developers, reviewers, and auditors. By reading your description, they should easily understand the changes proposed in this pull request. MUST: Reference the issue to resolve ### Single responsability Is RECOMMENDED to create single responsibility commits, but not mandatory. Anyway, you MUST enumerate the changes in a unitary way, e.g. ``` This PR contains: - Cleanup of xxxx, yyyy - Changed xxxx to yyyy in order to bla bla - Added xxxx function to ... - Refactored .... ``` ### Design choices RECOMMENDED to: - What types of design choices did you face? - What decisions you have made? - Any valuable information that could help reviewers to think critically Co-authored-by: Ming --- .../src/circuit_input_builder/access.rs | 203 +++++++++--------- 1 file changed, 105 insertions(+), 98 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/access.rs b/bus-mapping/src/circuit_input_builder/access.rs index 272eac3acf..9d83cb7c45 100644 --- a/bus-mapping/src/circuit_input_builder/access.rs +++ b/bus-mapping/src/circuit_input_builder/access.rs @@ -3,6 +3,9 @@ use eth_types::{evm_types::OpcodeId, Address, GethExecStep, GethExecTrace, ToAdd use ethers_core::utils::get_contract_address; use std::collections::{hash_map::Entry, HashMap, HashSet}; +use AccessValue::{Account, Code, Storage}; +use RW::{READ, WRITE}; + /// State and Code Access with "keys/index" used in the access operation. #[derive(Debug, PartialEq, Eq)] pub enum AccessValue { @@ -116,9 +119,6 @@ pub fn gen_state_access_trace( tx: ð_types::Transaction, geth_trace: &GethExecTrace, ) -> Result, Error> { - use AccessValue::{Account, Code, Storage}; - use RW::{READ, WRITE}; - let mut call_stack: Vec<(Address, CodeSource)> = Vec::new(); let mut accs = vec![Access::new(None, WRITE, Account { address: tx.from })]; if let Some(to) = tx.to { @@ -145,117 +145,124 @@ pub fn gen_state_access_trace( pop_call_stack = step.depth - 1 == next_step.depth; } - match step.op { - OpcodeId::SSTORE => { - let address = contract_address; - let key = step.stack.nth_last(0)?; - accs.push(Access::new(i, WRITE, Storage { address, key })); - } - OpcodeId::SLOAD => { - let address = contract_address; - let key = step.stack.nth_last(0)?; - accs.push(Access::new(i, READ, Storage { address, key })); - } - OpcodeId::SELFBALANCE => { - let address = contract_address; - accs.push(Access::new(i, READ, Account { address })); - } - OpcodeId::CODESIZE => { - if let CodeSource::Address(address) = code_source { + let result: Result<(), Error> = (|| { + match step.op { + OpcodeId::SSTORE => { + let address = contract_address; + let key = step.stack.nth_last(0)?; + accs.push(Access::new(i, WRITE, Storage { address, key })); + } + OpcodeId::SLOAD => { + let address = contract_address; + let key = step.stack.nth_last(0)?; + accs.push(Access::new(i, READ, Storage { address, key })); + } + OpcodeId::SELFBALANCE => { + let address = contract_address; + accs.push(Access::new(i, READ, Account { address })); + } + OpcodeId::CODESIZE => { + if let CodeSource::Address(address) = code_source { + accs.push(Access::new(i, READ, Code { address })); + } + } + OpcodeId::CODECOPY => { + if let CodeSource::Address(address) = code_source { + accs.push(Access::new(i, READ, Code { address })); + } + } + OpcodeId::BALANCE => { + let address = step.stack.nth_last(0)?.to_address(); + accs.push(Access::new(i, READ, Account { address })); + } + OpcodeId::EXTCODEHASH => { + let address = step.stack.nth_last(0)?.to_address(); + accs.push(Access::new(i, READ, Account { address })); + } + OpcodeId::EXTCODESIZE => { + let address = step.stack.nth_last(0)?.to_address(); accs.push(Access::new(i, READ, Code { address })); } - } - OpcodeId::CODECOPY => { - if let CodeSource::Address(address) = code_source { + OpcodeId::EXTCODECOPY => { + let address = step.stack.nth_last(0)?.to_address(); accs.push(Access::new(i, READ, Code { address })); } - } - OpcodeId::BALANCE => { - let address = step.stack.nth_last(0)?.to_address(); - accs.push(Access::new(i, READ, Account { address })); - } - OpcodeId::EXTCODEHASH => { - let address = step.stack.nth_last(0)?.to_address(); - accs.push(Access::new(i, READ, Account { address })); - } - OpcodeId::EXTCODESIZE => { - let address = step.stack.nth_last(0)?.to_address(); - accs.push(Access::new(i, READ, Code { address })); - } - OpcodeId::EXTCODECOPY => { - let address = step.stack.nth_last(0)?.to_address(); - accs.push(Access::new(i, READ, Code { address })); - } - OpcodeId::SELFDESTRUCT => { - let address = contract_address; - accs.push(Access::new(i, WRITE, Account { address })); - let address = step.stack.nth_last(0)?.to_address(); - accs.push(Access::new(i, WRITE, Account { address })); - } - OpcodeId::CREATE => { - if push_call_stack { - // Find CREATE result - let address = get_call_result(&geth_trace.struct_logs[index..]) - .unwrap_or_else(Word::zero) - .to_address(); - if !address.is_zero() { - accs.push(Access::new(i, WRITE, Account { address })); - accs.push(Access::new(i, WRITE, Code { address })); + OpcodeId::SELFDESTRUCT => { + let address = contract_address; + accs.push(Access::new(i, WRITE, Account { address })); + let address = step.stack.nth_last(0)?.to_address(); + accs.push(Access::new(i, WRITE, Account { address })); + } + OpcodeId::CREATE => { + if push_call_stack { + // Find CREATE result + let address = get_call_result(&geth_trace.struct_logs[index..]) + .unwrap_or_else(Word::zero) + .to_address(); + if !address.is_zero() { + accs.push(Access::new(i, WRITE, Account { address })); + accs.push(Access::new(i, WRITE, Code { address })); + } + call_stack.push((address, CodeSource::Address(address))); } - call_stack.push((address, CodeSource::Address(address))); } - } - OpcodeId::CREATE2 => { - if push_call_stack { - // Find CREATE2 result - let address = get_call_result(&geth_trace.struct_logs[index..]) - .unwrap_or_else(Word::zero) - .to_address(); - if !address.is_zero() { - accs.push(Access::new(i, WRITE, Account { address })); - accs.push(Access::new(i, WRITE, Code { address })); + OpcodeId::CREATE2 => { + if push_call_stack { + // Find CREATE2 result + let address = get_call_result(&geth_trace.struct_logs[index..]) + .unwrap_or_else(Word::zero) + .to_address(); + if !address.is_zero() { + accs.push(Access::new(i, WRITE, Account { address })); + accs.push(Access::new(i, WRITE, Code { address })); + } + call_stack.push((address, CodeSource::Address(address))); } - call_stack.push((address, CodeSource::Address(address))); } - } - OpcodeId::CALL => { - let address = contract_address; - accs.push(Access::new(i, WRITE, Account { address })); + OpcodeId::CALL => { + let address = contract_address; + accs.push(Access::new(i, WRITE, Account { address })); - let address = step.stack.nth_last(1)?.to_address(); - accs.push(Access::new(i, WRITE, Account { address })); - accs.push(Access::new(i, READ, Code { address })); - if push_call_stack { - call_stack.push((address, CodeSource::Address(address))); + let address = step.stack.nth_last(1)?.to_address(); + accs.push(Access::new(i, WRITE, Account { address })); + accs.push(Access::new(i, READ, Code { address })); + if push_call_stack { + call_stack.push((address, CodeSource::Address(address))); + } } - } - OpcodeId::CALLCODE => { - let address = contract_address; - accs.push(Access::new(i, WRITE, Account { address })); + OpcodeId::CALLCODE => { + let address = contract_address; + accs.push(Access::new(i, WRITE, Account { address })); - let address = step.stack.nth_last(1)?.to_address(); - accs.push(Access::new(i, WRITE, Account { address })); - accs.push(Access::new(i, READ, Code { address })); - if push_call_stack { - call_stack.push((address, CodeSource::Address(address))); + let address = step.stack.nth_last(1)?.to_address(); + accs.push(Access::new(i, WRITE, Account { address })); + accs.push(Access::new(i, READ, Code { address })); + if push_call_stack { + call_stack.push((address, CodeSource::Address(address))); + } } - } - OpcodeId::DELEGATECALL => { - let address = step.stack.nth_last(1)?.to_address(); - accs.push(Access::new(i, READ, Code { address })); - if push_call_stack { - call_stack.push((contract_address, CodeSource::Address(address))); + OpcodeId::DELEGATECALL => { + let address = step.stack.nth_last(1)?.to_address(); + accs.push(Access::new(i, READ, Code { address })); + if push_call_stack { + call_stack.push((contract_address, CodeSource::Address(address))); + } } - } - OpcodeId::STATICCALL => { - let address = step.stack.nth_last(1)?.to_address(); - accs.push(Access::new(i, READ, Code { address })); - if push_call_stack { - call_stack.push((address, CodeSource::Address(address))); + OpcodeId::STATICCALL => { + let address = step.stack.nth_last(1)?.to_address(); + accs.push(Access::new(i, READ, Code { address })); + if push_call_stack { + call_stack.push((address, CodeSource::Address(address))); + } } + _ => {} } - _ => {} + Ok(()) + })(); + if let Err(e) = result { + log::warn!("err when parsing access: {:?}, step {:?}", e, step); } + if pop_call_stack { if call_stack.len() == 1 { return Err(Error::InvalidGethExecStep( From fa320ea0435320a8312a383dfa0eb9e8bcd61dc8 Mon Sep 17 00:00:00 2001 From: xiaodino Date: Wed, 12 Apr 2023 07:52:13 -0700 Subject: [PATCH 004/102] Remove code duplication between returndatacopy and others (#1340) ### Description Remove code duplication between returndatacopy and others as they use similar test codes to construct bytecode for testing. ### Issue Link https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1324 ### Type of change - [x] Refactor code ### Contents Remove code duplication in unit tests between returndatacopy, balance, calldataload and others. The unit tests should behave the same. ### Rationale It's easier to manage the mock bytecode when we move similar code into one place. ### How Has This Been Tested? Use the command `make test` to run unit tests
--------- Co-authored-by: Brecht Devos --- .../src/circuit_input_builder/tracer_tests.rs | 92 +++++-------------- bus-mapping/src/evm/opcodes/balance.rs | 6 +- bus-mapping/src/evm/opcodes/calldatacopy.rs | 75 +++++---------- bus-mapping/src/evm/opcodes/calldataload.rs | 30 +++--- .../opcodes/error_return_data_outofbound.rs | 6 +- bus-mapping/src/evm/opcodes/return_revert.rs | 24 +---- bus-mapping/src/evm/opcodes/returndatacopy.rs | 26 +----- bus-mapping/src/evm/opcodes/returndatasize.rs | 30 ++---- bus-mapping/src/evm/opcodes/sha3.rs | 2 +- eth-types/src/bytecode.rs | 72 ++++++++++++--- eth-types/src/lib.rs | 23 +++++ mock/src/lib.rs | 80 +++++++++++++++- .../src/evm_circuit/execution/address.rs | 27 ++---- .../src/evm_circuit/execution/balance.rs | 41 +++------ .../src/evm_circuit/execution/calldatacopy.rs | 60 +++++------- .../src/evm_circuit/execution/calldataload.rs | 45 ++++----- .../execution/error_invalid_opcode.rs | 28 ++---- .../evm_circuit/execution/error_oog_exp.rs | 36 +++----- .../execution/error_oog_sload_sstore.rs | 36 ++++---- .../execution/error_return_data_oo_bound.rs | 12 +-- .../src/evm_circuit/execution/extcodesize.rs | 33 +++---- .../evm_circuit/execution/returndatacopy.rs | 33 +++---- .../evm_circuit/execution/returndatasize.rs | 34 +++---- 23 files changed, 380 insertions(+), 471 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index 2033ddd23f..39dc4fbeb0 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -357,12 +357,8 @@ fn tracer_err_address_collision() { // that outputs the same, which will lead to the same new // contract address. let code_creator = bytecode! { - PUSH1(0x00) // value - PUSH1(0x00) // offset - MSTORE - PUSH1(0x01) // length - PUSH1(0x00) // offset - RETURN + .mstore(0x00, 0x00) + .return_bytecode(0x00, 0x01) }; // code_a calls code_b which executes code_creator in CREATE2 @@ -488,12 +484,8 @@ fn tracer_create_collision_free() { // that outputs not the same, which will lead to the different new // contract address. let code_creator = bytecode! { - PUSH1(0x00) // value - PUSH1(0x00) // offset - MSTORE - PUSH1(0x01) // length - PUSH1(0x00) // offset - RETURN + .mstore(0x00, 0x00) + .return_bytecode(0x00, 0x01) }; // code_a calls code_b which executes code_creator in CREATE2 @@ -632,12 +624,8 @@ fn tracer_err_code_store_out_of_gas() { // exhaust the gas to store the code. let code_len = 0x100; let code_creator = bytecode! { - PUSH1(Word::zero()) // value - PUSH32(code_len) // offset - MSTORE - PUSH32(code_len) // length - PUSH1(0x00) // offset - RETURN + .mstore(code_len, Word::zero()) + .return_bytecode(0x00, code_len) }; // code_a calls code_b which executes code_creator in CREATE @@ -729,12 +717,8 @@ fn tracer_err_code_store_out_of_gas_tx_deploy() { // exhaust the gas to store the code. let code_len = 0x100; let code_creator = bytecode! { - PUSH1(Word::zero()) // value - PUSH32(code_len) // offset - MSTORE - PUSH32(code_len) // length - PUSH1(0x00) // offset - RETURN + .mstore(code_len, Word::zero()) + .return_bytecode(0x00, code_len) }; // Get the execution steps from the external tracer @@ -794,12 +778,8 @@ fn tracer_err_invalid_code() { // code_creator outputs byte array that starts with 0xef, which is // invalid code. let code_creator = bytecode! { - PUSH32(word!("0xef00000000000000000000000000000000000000000000000000000000000000")) // value - PUSH1(0x00) // offset - MSTORE - PUSH1(0x01) // length - PUSH1(0x00) // offset - RETURN + .mstore(0x00, word!("0xef00000000000000000000000000000000000000000000000000000000000000")) + .return_bytecode(0x00, 0x01) }; // code_a calls code_b which executes code_creator in CREATE @@ -900,12 +880,8 @@ fn tracer_err_max_code_size_exceeded() { // trigger the max code size limit. let code_len = 0x6000 + 1; let code_creator = bytecode! { - PUSH1(Word::zero()) // value - PUSH32(code_len) // offset - MSTORE - PUSH32(code_len) // length - PUSH1(0x00) // offset - RETURN + .mstore(code_len, Word::zero()) + .return_bytecode(0x00, code_len) }; // code_a calls code_b which executes code_creator in CREATE @@ -997,12 +973,8 @@ fn tracer_err_max_code_size_exceeded_tx_deploy() { // trigger the max code size limit. let code_len = 0x6000 + 1; let code_creator = bytecode! { - PUSH1(Word::zero()) // value - PUSH32(code_len) // offset - MSTORE - PUSH32(code_len) // length - PUSH1(0x00) // offset - RETURN + .mstore(code_len, Word::zero()) + .return_bytecode(0x00, code_len) }; // Get the execution steps from the external tracer @@ -1050,9 +1022,7 @@ fn tracer_err_max_code_size_exceeded_tx_deploy() { fn tracer_create_stop() { // code_creator doesn't output anything because it stops. let code_creator = bytecode! { - PUSH32(word!("0xef00000000000000000000000000000000000000000000000000000000000000")) // value - PUSH1(0x00) // offset - MSTORE + .mstore(0x00, word!("0xef00000000000000000000000000000000000000000000000000000000000000")) PUSH1(0x01) // length PUSH1(0x00) // offset STOP @@ -1451,12 +1421,8 @@ fn tracer_err_return_data_out_of_bounds() { PUSH2(0xaa) }; let code_b = bytecode! { - PUSH2(0x42) // value - PUSH2(0x00) // offset - MSTORE - PUSH1(0x01) // length - PUSH1(0x00) // offset - RETURN + .mstore(0x00, 0x42) + .return_bytecode(0x00, 0x01) }; // Get the execution steps from the external tracer let block: GethData = TestContext::<3, 2>::new_with_logger_config( @@ -1510,9 +1476,7 @@ fn tracer_err_gas_uint_overflow() { // MSTORE a value at an offset so high that the gast cost is big enough // to overflow an uint64 let code = bytecode! { - PUSH32(0x42) // value - PUSH32(0x100_0000_0000_0000_0000_u128) // offset - MSTORE + .mstore(0x100_0000_0000_0000_0000_u128, 0x42) }; let block: GethData = TestContext::<2, 1>::new_with_logger_config( None, @@ -1789,12 +1753,8 @@ fn tracer_err_stack_underflow() { fn create2_address() { // code_creator outputs 0x6050. let code_creator = bytecode! { - PUSH32(word!("0x6050000000000000000000000000000000000000000000000000000000000000")) // value - PUSH1(0x00) // offset - MSTORE - PUSH1(0x02) // length - PUSH1(0x00) // offset - RETURN + .mstore(0x00, word!("0x6050000000000000000000000000000000000000000000000000000000000000")) + .return_bytecode(0x00, 0x02) }; // code_a calls code_b which executes code_creator in CREATE @@ -1891,12 +1851,8 @@ fn create2_address() { fn create_address() { // code_creator outputs 0x6050. let code_creator = bytecode! { - PUSH32(word!("0x6050000000000000000000000000000000000000000000000000000000000000")) // value - PUSH1(0x00) // offset - MSTORE - PUSH1(0x02) // length - PUSH1(0x00) // offset - RETURN + .mstore(0x00, word!("0x6050000000000000000000000000000000000000000000000000000000000000")) + .return_bytecode(0x00, 0x02) }; // code_a calls code_b which executes code_creator in CREATE @@ -2021,9 +1977,7 @@ fn test_gen_access_trace() { PUSH2(0xaa) }; let code_b = bytecode! { - PUSH32(word!("0x1234567890000000000000000000abcdef000000000000000000112233445566")) // value - PUSH1(0x01) // offset - MSTORE + .mstore(0x01, word!("0x1234567890000000000000000000abcdef000000000000000000112233445566")) PUSH1(0x01) // value PUSH1(0x02) // key SSTORE diff --git a/bus-mapping/src/evm/opcodes/balance.rs b/bus-mapping/src/evm/opcodes/balance.rs index 32a4a6c597..b30fd1acfc 100644 --- a/bus-mapping/src/evm/opcodes/balance.rs +++ b/bus-mapping/src/evm/opcodes/balance.rs @@ -125,14 +125,12 @@ mod balance_tests { let mut code = Bytecode::default(); if is_warm { code.append(&bytecode! { - PUSH20(address.to_word()) - BALANCE + .balance(address) POP }); } code.append(&bytecode! { - PUSH20(address.to_word()) - BALANCE + .balance(address) STOP }); diff --git a/bus-mapping/src/evm/opcodes/calldatacopy.rs b/bus-mapping/src/evm/opcodes/calldatacopy.rs index 22e319afe7..2edd2879ba 100644 --- a/bus-mapping/src/evm/opcodes/calldatacopy.rs +++ b/bus-mapping/src/evm/opcodes/calldatacopy.rs @@ -183,10 +183,14 @@ mod calldatacopy_tests { bytecode, evm_types::{OpcodeId, StackAddress}, geth_types::GethData, - ToWord, Word, + Word, }; - use mock::test_ctx::{helpers::*, TestContext}; + use mock::{ + generate_mock_call_bytecode, + test_ctx::{helpers::*, TestContext}, + MockCallBytecodeParams, + }; use pretty_assertions::assert_eq; #[test] @@ -198,10 +202,7 @@ mod calldatacopy_tests { let offset = 0x00usize; let copy_size = 0x10usize; let code_b = bytecode! { - PUSH32(copy_size) // size - PUSH32(offset) // offset - PUSH32(dst_offset) // dst_offset - CALLDATACOPY + .calldatacopy(dst_offset, offset, copy_size) STOP }; @@ -211,24 +212,16 @@ mod calldatacopy_tests { .take(24) .chain(pushdata.clone()) .collect::>(); + let call_data_length = 0x20usize; let call_data_offset = 0x10usize; - let code_a = bytecode! { - // populate memory in A's context. - PUSH8(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call addr_b. - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH1(call_data_length) // argsLength - PUSH1(call_data_offset) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata, + call_data_length, + call_data_offset, + ..MockCallBytecodeParams::default() + }); // Get the execution steps from the external tracer let block: GethData = TestContext::<3, 1>::new( @@ -384,14 +377,8 @@ mod calldatacopy_tests { let (addr_a, addr_b) = (mock::MOCK_ACCOUNTS[0], mock::MOCK_ACCOUNTS[1]); // code B gets called by code A, so the call is an internal call. - let dst_offset = 0x00usize; - let offset = 0x00usize; - let copy_size = 0x50usize; let code_b = bytecode! { - PUSH32(copy_size) // size - PUSH32(offset) // offset - PUSH32(dst_offset) // dst_offset - CALLDATACOPY + .calldatacopy(0x00usize, 0x00usize, 0x50usize) STOP }; @@ -401,24 +388,13 @@ mod calldatacopy_tests { .take(24) .chain(pushdata.clone()) .collect::>(); - let call_data_length = 0x20usize; - let call_data_offset = 0x10usize; - let code_a = bytecode! { - // populate memory in A's context. - PUSH8(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call addr_b. - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH1(call_data_length) // argsLength - PUSH1(call_data_offset) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata, + call_data_length: 0x20usize, + call_data_offset: 0x10usize, + ..MockCallBytecodeParams::default() + }); // Get the execution steps from the external tracer let block: GethData = TestContext::<3, 1>::new( @@ -452,10 +428,7 @@ mod calldatacopy_tests { let calldata = vec![1, 3, 5, 7, 9, 2, 4, 6, 8]; let calldata_len = calldata.len(); let code = bytecode! { - PUSH32(size) - PUSH32(offset) - PUSH32(dst_offset) - CALLDATACOPY + .calldatacopy(dst_offset, offset, size) STOP }; diff --git a/bus-mapping/src/evm/opcodes/calldataload.rs b/bus-mapping/src/evm/opcodes/calldataload.rs index dacee4e721..c75336b51b 100644 --- a/bus-mapping/src/evm/opcodes/calldataload.rs +++ b/bus-mapping/src/evm/opcodes/calldataload.rs @@ -102,9 +102,12 @@ mod calldataload_tests { bytecode, evm_types::{OpcodeId, StackAddress}, geth_types::GethData, - ToWord, Word, + Word, + }; + use mock::{ + generate_mock_call_bytecode, test_ctx::helpers::account_0_code_account_1_no_code, + MockCallBytecodeParams, TestContext, }; - use mock::{test_ctx::helpers::account_0_code_account_1_no_code, TestContext}; use rand::random; use crate::{circuit_input_builder::ExecState, mock::BlockData, operation::StackOp}; @@ -138,22 +141,13 @@ mod calldataload_tests { if memory_a.len() < call_data_length { memory_a.resize(call_data_length, 0); } - let code_a = bytecode! { - // populate memory in A's context. - PUSH32(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call addr_b - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH1(call_data_length) // argsLength - PUSH1(call_data_offset) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata, + call_data_length, + call_data_offset, + ..MockCallBytecodeParams::default() + }); // Get the execution steps from the external tracer let block: GethData = TestContext::<3, 1>::new( diff --git a/bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs b/bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs index f432499111..5fa9d1c309 100644 --- a/bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs +++ b/bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs @@ -80,16 +80,16 @@ impl Opcode for ErrorReturnDataOutOfBound { mod tests { use super::*; use crate::{circuit_input_builder::ExecState, mock::BlockData, operation::RW}; - use eth_types::{bytecode, evm_types::OpcodeId, geth_types::GethData, word}; + use eth_types::{bytecode, evm_types::OpcodeId, geth_types::GethData}; use mock::{ test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, - TestContext, + TestContext, MOCK_DEPLOYED_CONTRACT_BYTECODE, }; #[test] fn test_returndata_error() { let code = bytecode! { - PUSH21(word!("6B6020600060003760206000F3600052600C6014F3")) + PUSH21(*MOCK_DEPLOYED_CONTRACT_BYTECODE) PUSH1(0) MSTORE diff --git a/bus-mapping/src/evm/opcodes/return_revert.rs b/bus-mapping/src/evm/opcodes/return_revert.rs index 484b1c0ef3..8c56064753 100644 --- a/bus-mapping/src/evm/opcodes/return_revert.rs +++ b/bus-mapping/src/evm/opcodes/return_revert.rs @@ -242,33 +242,13 @@ mod return_tests { use eth_types::{bytecode, geth_types::GethData, word}; use mock::{ test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, - TestContext, + TestContext, MOCK_DEPLOYED_CONTRACT_BYTECODE, }; #[test] fn test_ok() { - // // deployed contract - // PUSH1 0x20 - // PUSH1 0 - // PUSH1 0 - // CALLDATACOPY - // PUSH1 0x20 - // PUSH1 0 - // RETURN - // - // bytecode: 0x6020600060003760206000F3 - // - // // constructor - // PUSH12 0x6020600060003760206000F3 - // PUSH1 0 - // MSTORE - // PUSH1 0xC - // PUSH1 0x14 - // RETURN - // - // bytecode: 0x6B6020600060003760206000F3600052600C6014F3 let code = bytecode! { - PUSH21(word!("6B6020600060003760206000F3600052600C6014F3")) + PUSH21(*MOCK_DEPLOYED_CONTRACT_BYTECODE) PUSH1(0) MSTORE diff --git a/bus-mapping/src/evm/opcodes/returndatacopy.rs b/bus-mapping/src/evm/opcodes/returndatacopy.rs index 7c63965bef..a0e9be1ea1 100644 --- a/bus-mapping/src/evm/opcodes/returndatacopy.rs +++ b/bus-mapping/src/evm/opcodes/returndatacopy.rs @@ -170,36 +170,16 @@ fn gen_copy_event( #[cfg(test)] mod return_tests { use crate::mock::BlockData; - use eth_types::{bytecode, geth_types::GethData, word}; + use eth_types::{bytecode, geth_types::GethData}; use mock::{ test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, - TestContext, + TestContext, MOCK_DEPLOYED_CONTRACT_BYTECODE, }; #[test] fn test_ok() { - // // deployed contract - // PUSH1 0x20 - // PUSH1 0 - // PUSH1 0 - // CALLDATACOPY - // PUSH1 0x20 - // PUSH1 0 - // RETURN - // - // bytecode: 0x6020600060003760206000F3 - // - // // constructor - // PUSH12 0x6020600060003760206000F3 - // PUSH1 0 - // MSTORE - // PUSH1 0xC - // PUSH1 0x14 - // RETURN - // - // bytecode: 0x6B6020600060003760206000F3600052600C6014F3 let code = bytecode! { - PUSH21(word!("6B6020600060003760206000F3600052600C6014F3")) + PUSH21(*MOCK_DEPLOYED_CONTRACT_BYTECODE) PUSH1(0) MSTORE diff --git a/bus-mapping/src/evm/opcodes/returndatasize.rs b/bus-mapping/src/evm/opcodes/returndatasize.rs index 69017e44a5..ca576be396 100644 --- a/bus-mapping/src/evm/opcodes/returndatasize.rs +++ b/bus-mapping/src/evm/opcodes/returndatasize.rs @@ -47,37 +47,19 @@ mod returndatasize_tests { bytecode, evm_types::{OpcodeId, StackAddress}, geth_types::GethData, - word, Word, + Word, + }; + use mock::{ + test_ctx::{helpers::*, TestContext}, + MOCK_DEPLOYED_CONTRACT_BYTECODE, }; - use mock::test_ctx::{helpers::*, TestContext}; use pretty_assertions::assert_eq; #[test] fn test_ok() { let return_data_size = 0x20; - - // // deployed contract - // PUSH1 0x20 - // PUSH1 0 - // PUSH1 0 - // CALLDATACOPY - // PUSH1 0x20 - // PUSH1 0 - // RETURN - // - // bytecode: 0x6020600060003760206000F3 - // - // // constructor - // PUSH12 0x6020600060003760206000F3 - // PUSH1 0 - // MSTORE - // PUSH1 0xC - // PUSH1 0x14 - // RETURN - // - // bytecode: 0x6B6020600060003760206000F3600052600C6014F3 let code = bytecode! { - PUSH21(word!("6B6020600060003760206000F3600052600C6014F3")) + PUSH21(*MOCK_DEPLOYED_CONTRACT_BYTECODE) PUSH1(0) MSTORE diff --git a/bus-mapping/src/evm/opcodes/sha3.rs b/bus-mapping/src/evm/opcodes/sha3.rs index 47c964b9f4..75c2cf1a49 100644 --- a/bus-mapping/src/evm/opcodes/sha3.rs +++ b/bus-mapping/src/evm/opcodes/sha3.rs @@ -139,7 +139,7 @@ pub mod sha3_tests { }; memory.extend_from_slice(&mem_value); code.push(32, Word::from_big_endian(&mem_value)); - code.push(32, (32 * i).into()); + code.push(32, 32 * i); code.write_op(OpcodeId::MSTORE); } // append SHA3 related opcodes at the tail end. diff --git a/eth-types/src/bytecode.rs b/eth-types/src/bytecode.rs index 406a9f51a6..e62d71ec87 100644 --- a/eth-types/src/bytecode.rs +++ b/eth-types/src/bytecode.rs @@ -1,6 +1,6 @@ //! EVM byte code generator -use crate::{evm_types::OpcodeId, Bytes, Word}; +use crate::{evm_types::OpcodeId, Bytes, ToWord, Word}; use std::{collections::HashMap, str::FromStr}; /// Error type for Bytecode related failures @@ -95,8 +95,9 @@ impl Bytecode { } /// Push - pub fn push(&mut self, n: u8, value: Word) -> &mut Self { + pub fn push(&mut self, n: u8, value: T) -> &mut Self { debug_assert!((1..=32).contains(&n), "invalid push"); + let value = value.to_word(); // Write the op code self.write_op((OpcodeId::push_n(n)).expect("valid push size")); @@ -150,15 +151,15 @@ impl Bytecode { /// Call a contract #[allow(clippy::too_many_arguments)] - pub fn call( + pub fn call( &mut self, - gas: Word, - address: Word, - value: Word, - mem_in: Word, - mem_in_size: Word, - mem_out: Word, - mem_out_size: Word, + gas: T, + address: U, + value: V, + mem_in: W, + mem_in_size: X, + mem_out: Y, + mem_out_size: Z, ) -> &mut Self { self.append(&crate::bytecode! { PUSH32(mem_out_size) @@ -173,6 +174,51 @@ impl Bytecode { self } + /// Balance + pub fn balance(&mut self, address: T) -> &mut Self { + self.append(&crate::bytecode! { + PUSH20(address) + BALANCE + }); + self + } + + /// mstore + pub fn mstore(&mut self, offset: T, value: U) -> &mut Self { + self.append(&crate::bytecode! { + PUSH32(value) + PUSH32(offset) + MSTORE + }); + self + } + + /// calldatacopy + pub fn calldatacopy( + &mut self, + dst_offset: T, + offset: U, + size: V, + ) -> &mut Self { + self.append(&crate::bytecode! { + PUSH32(size) + PUSH32(offset) + PUSH32(dst_offset) + CALLDATACOPY + }); + self + } + + /// return + pub fn return_bytecode(&mut self, offset: T, size: U) -> &mut Self { + self.append(&crate::bytecode! { + PUSH32(size) + PUSH32(offset) + RETURN + }); + self + } + /// Generate the diassembly pub fn disasm(&self) -> String { let mut asm = String::new(); @@ -335,7 +381,7 @@ macro_rules! bytecode_internal { ($code:ident, $x:ident ($v:expr) $($rest:tt)*) => {{ debug_assert!($crate::evm_types::OpcodeId::$x.is_push(), "invalid push"); let n = $crate::evm_types::OpcodeId::$x.postfix().expect("opcode with postfix"); - $code.push(n, $v.into()); + $code.push(n, $v); $crate::bytecode_internal!($code, $($rest)*); }}; // Default opcode without any inputs @@ -350,8 +396,8 @@ macro_rules! bytecode_internal { $crate::bytecode_internal!($code, $($rest)*); }}; // Function calls - ($code:ident, .$function:ident ($($args:expr),*) $($rest:tt)*) => {{ - $code.$function($($args.into(),)*); + ($code:ident, .$function:ident ($($args:expr),* $(,)?) $($rest:tt)*) => {{ + $code.$function($($args,)*); $crate::bytecode_internal!($code, $($rest)*); }}; } diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index b59f614f0c..ab40c488e0 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -202,6 +202,12 @@ impl ToWord for u64 { } } +impl ToWord for u128 { + fn to_word(&self) -> Word { + Word::from(*self) + } +} + impl ToWord for usize { fn to_word(&self) -> Word { u64::try_from(*self) @@ -210,6 +216,23 @@ impl ToWord for usize { } } +impl ToWord for i32 { + fn to_word(&self) -> Word { + let value = Word::from(self.unsigned_abs() as u64); + if self.is_negative() { + value.overflowing_neg().0 + } else { + value + } + } +} + +impl ToWord for Word { + fn to_word(&self) -> Word { + *self + } +} + impl ToScalar for Address { fn to_scalar(&self) -> Option { let mut bytes = [0u8; 32]; diff --git a/mock/src/lib.rs b/mock/src/lib.rs index 3a3c176e8c..aad706f3e2 100644 --- a/mock/src/lib.rs +++ b/mock/src/lib.rs @@ -1,6 +1,6 @@ //! Mock types and functions to generate GethData used for tests -use eth_types::{address, Address, Bytes, Word}; +use eth_types::{address, bytecode, bytecode::Bytecode, word, Address, Bytes, Word}; use ethers_signers::LocalWallet; use lazy_static::lazy_static; use rand::SeedableRng; @@ -57,6 +57,27 @@ lazy_static! { LocalWallet::new(&mut rng), ] }; + /// Mock EVM bytecode for a deployed contract. + /// PUSH1 0x20 + /// PUSH1 0 + /// PUSH1 0 + /// CALLDATACOPY + /// PUSH1 0x20 + /// PUSH1 0 + /// RETURN + /// + /// bytecode: 0x6020600060003760206000F3 + /// + /// // constructor + /// PUSH12 0x6020600060003760206000F3 + /// PUSH1 0 + /// MSTORE + /// PUSH1 0xC + /// PUSH1 0x14 + /// RETURN + /// + /// bytecode: 0x6B6020600060003760206000F3600052600C6014F3 + pub static ref MOCK_DEPLOYED_CONTRACT_BYTECODE: Word = word!("6B6020600060003760206000F3600052600C6014F3"); } /// Generate a [`Word`] which corresponds to a certain amount of ETH. @@ -68,3 +89,60 @@ pub fn eth(x: u64) -> Word { pub fn gwei(x: u64) -> Word { Word::from(x) * Word::from(10u64.pow(9)) } + +/// Holds the parameters for generating mock EVM bytecode for a contract call +pub struct MockCallBytecodeParams { + /// The address to call with the generated bytecode + pub address: Address, + /// The data to be passed as arguments to the contract function. + pub pushdata: Vec, + /// The offset in memory where the return data will be stored. + pub return_data_offset: usize, + /// The size of the return data. + pub return_data_size: usize, + /// The length of the call data. + pub call_data_length: usize, + /// The offset in memory where the call data will be stored. + pub call_data_offset: usize, + /// The amount of gas to be used for the contract call. + pub gas: u64, + /// The instructions to be executed after the contract call. + pub instructions_after_call: Bytecode, +} + +/// Set default parameters for MockCallBytecodeParams +impl Default for MockCallBytecodeParams { + fn default() -> Self { + MockCallBytecodeParams { + address: address!("0x0000000000000000000000000000000000000000"), + pushdata: Vec::new(), + return_data_offset: 0x00usize, + return_data_size: 0x00usize, + call_data_length: 0x00usize, + call_data_offset: 0x00usize, + gas: 0x1_0000u64, + instructions_after_call: Bytecode::default(), + } + } +} + +/// Generate mock EVM bytecode that performs a contract call +pub fn generate_mock_call_bytecode(params: MockCallBytecodeParams) -> Bytecode { + bytecode! { + .mstore( + 0u64, + Word::from_big_endian(¶ms.pushdata) + ) + .call( + params.gas, + params.address, + 0u64, + params.call_data_offset, + params.call_data_length, + params.return_data_size, + params.return_data_offset, + ) + .append(¶ms.instructions_after_call) + STOP + } +} diff --git a/zkevm-circuits/src/evm_circuit/execution/address.rs b/zkevm-circuits/src/evm_circuit/execution/address.rs index 494740d68c..bca707c3b8 100644 --- a/zkevm-circuits/src/evm_circuit/execution/address.rs +++ b/zkevm-circuits/src/evm_circuit/execution/address.rs @@ -90,8 +90,8 @@ impl ExecutionGadget for AddressGadget { #[cfg(test)] mod test { use crate::{evm_circuit::test::rand_bytes, test_util::CircuitTestBuilder}; - use eth_types::{bytecode, ToWord, Word}; - use mock::test_ctx::TestContext; + use eth_types::{bytecode, Word}; + use mock::{generate_mock_call_bytecode, test_ctx::TestContext, MockCallBytecodeParams}; fn test_root_ok() { let bytecode = bytecode! { @@ -116,22 +116,13 @@ mod test { // code A calls code B. let pushdata = rand_bytes(8); - let code_a = bytecode! { - // populate memory in A's context. - PUSH8(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call ADDR_B. - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH32(call_data_length) // argsLength - PUSH32(call_data_offset) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata, + call_data_length, + call_data_offset, + ..MockCallBytecodeParams::default() + }); let ctx = TestContext::<3, 1>::new( None, diff --git a/zkevm-circuits/src/evm_circuit/execution/balance.rs b/zkevm-circuits/src/evm_circuit/execution/balance.rs index a806dd3833..04ed6277ca 100644 --- a/zkevm-circuits/src/evm_circuit/execution/balance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/balance.rs @@ -146,11 +146,9 @@ impl ExecutionGadget for BalanceGadget { #[cfg(test)] mod test { use crate::{evm_circuit::test::rand_bytes, test_util::CircuitTestBuilder}; - use eth_types::{ - address, bytecode, geth_types::Account, Address, Bytecode, ToWord, Word, U256, - }; + use eth_types::{address, bytecode, geth_types::Account, Address, Bytecode, Word, U256}; use lazy_static::lazy_static; - use mock::TestContext; + use mock::{generate_mock_call_bytecode, test_ctx::TestContext, MockCallBytecodeParams}; lazy_static! { static ref TEST_ADDRESS: Address = address!("0xaabbccddee000000000000000000000000000000"); @@ -204,14 +202,12 @@ mod test { let mut code = Bytecode::default(); if is_warm { code.append(&bytecode! { - PUSH20(address.to_word()) - BALANCE + .balance(address) POP }); } code.append(&bytecode! { - PUSH20(address.to_word()) - BALANCE + .balance(address) STOP }); @@ -257,35 +253,24 @@ mod test { let mut code_b = Bytecode::default(); if is_warm { code_b.append(&bytecode! { - PUSH20(address.to_word()) - BALANCE + .balance(address) POP }); } code_b.append(&bytecode! { - PUSH20(address.to_word()) - BALANCE + .balance(address) STOP }); // code A calls code B. let pushdata = rand_bytes(8); - let code_a = bytecode! { - // populate memory in A's context. - PUSH8(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call ADDR_B. - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH32(call_data_length) // argsLength - PUSH32(call_data_offset) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata, + call_data_length, + call_data_offset, + ..MockCallBytecodeParams::default() + }); let ctx = TestContext::<4, 1>::new( None, diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index 3a2892a686..69433e3910 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -251,10 +251,14 @@ impl ExecutionGadget for CallDataCopyGadget { mod test { use crate::{evm_circuit::test::rand_bytes, test_util::CircuitTestBuilder}; use bus_mapping::circuit_input_builder::CircuitsParams; - use eth_types::{bytecode, ToWord, Word}; - use mock::test_ctx::{helpers::*, TestContext}; - - fn test_ok_root( + use eth_types::{bytecode, Word}; + use mock::{ + generate_mock_call_bytecode, + test_ctx::{helpers::*, TestContext}, + MockCallBytecodeParams, + }; + + fn test_root_ok( call_data_length: usize, memory_offset: usize, data_offset: usize, @@ -292,7 +296,7 @@ mod test { .run(); } - fn test_ok_internal( + fn test_internal_ok( call_data_offset: usize, call_data_length: usize, dst_offset: usize, @@ -303,31 +307,17 @@ mod test { // code B gets called by code A, so the call is an internal call. let code_b = bytecode! { - PUSH32(length) // size - PUSH32(offset) // offset - PUSH32(dst_offset) // dst_offset - CALLDATACOPY + .calldatacopy(dst_offset, offset, length) STOP }; - // code A calls code B. - let pushdata = rand_bytes(8); - let code_a = bytecode! { - // populate memory in A's context. - PUSH8(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call ADDR_B. - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH32(call_data_length) // argsLength - PUSH32(call_data_offset) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata: rand_bytes(32), + call_data_length, + call_data_offset, + ..MockCallBytecodeParams::default() + }); let ctx = TestContext::<3, 1>::new( None, @@ -350,25 +340,25 @@ mod test { #[test] fn calldatacopy_gadget_simple() { - test_ok_root(0x40, 0x40, 0x00, 10); - test_ok_internal(0x40, 0x40, 0xA0, 0x10, 10); + test_root_ok(0x40, 0x40, 0x00, 10); + test_internal_ok(0x40, 0x40, 0xA0, 0x10, 10); } #[test] fn calldatacopy_gadget_large() { - test_ok_root(0x204, 0x103, 0x102, 0x101); - test_ok_internal(0x30, 0x204, 0x103, 0x102, 0x101); + test_root_ok(0x204, 0x103, 0x102, 0x101); + test_internal_ok(0x30, 0x204, 0x103, 0x102, 0x101); } #[test] fn calldatacopy_gadget_out_of_bound() { - test_ok_root(0x40, 0x40, 0x20, 40); - test_ok_internal(0x40, 0x20, 0xA0, 0x28, 10); + test_root_ok(0x40, 0x40, 0x20, 40); + test_internal_ok(0x40, 0x20, 0xA0, 0x28, 10); } #[test] fn calldatacopy_gadget_zero_length() { - test_ok_root(0x40, 0x40, 0x00, 0); - test_ok_internal(0x40, 0x40, 0xA0, 0x10, 0); + test_root_ok(0x40, 0x40, 0x00, 0); + test_internal_ok(0x40, 0x40, 0xA0, 0x10, 0); } } diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs index a18f69cc6b..fcfe7cf704 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs @@ -243,15 +243,19 @@ impl ExecutionGadget for CallDataLoadGadget { #[cfg(test)] mod test { use crate::{evm_circuit::test::rand_bytes, test_util::CircuitTestBuilder}; - use eth_types::{bytecode, ToWord, Word}; - use mock::TestContext; + use eth_types::{bytecode, Word}; + use mock::{generate_mock_call_bytecode, MockCallBytecodeParams, TestContext}; - fn test_root_ok(offset: usize) { - let bytecode = bytecode! { + fn test_bytecode(offset: usize) -> eth_types::Bytecode { + bytecode! { PUSH32(Word::from(offset)) CALLDATALOAD STOP - }; + } + } + + fn test_root_ok(offset: usize) { + let bytecode = test_bytecode(offset); CircuitTestBuilder::new_from_test_ctx( TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(), @@ -263,29 +267,14 @@ mod test { let (addr_a, addr_b) = (mock::MOCK_ACCOUNTS[0], mock::MOCK_ACCOUNTS[1]); // code B gets called by code A, so the call is an internal call. - let code_b = bytecode! { - PUSH32(Word::from(offset)) - CALLDATALOAD - STOP - }; - - let pushdata = rand_bytes(32); - let code_a = bytecode! { - // populate memory in A's context. - PUSH32(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call addr_b - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH32(call_data_length) // argsLength - PUSH32(call_data_offset) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_b = test_bytecode(offset); + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata: rand_bytes(32), + call_data_length, + call_data_offset, + ..MockCallBytecodeParams::default() + }); let ctx = TestContext::<3, 1>::new( None, diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs index fbc1709096..4febed2a73 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs @@ -67,9 +67,9 @@ impl ExecutionGadget for ErrorInvalidOpcodeGadget { #[cfg(test)] mod test { use crate::{evm_circuit::test::rand_bytes, test_util::CircuitTestBuilder}; - use eth_types::{bytecode, bytecode::Bytecode, ToWord, Word}; + use eth_types::{bytecode::Bytecode, Word}; use lazy_static::lazy_static; - use mock::TestContext; + use mock::{generate_mock_call_bytecode, MockCallBytecodeParams, TestContext}; lazy_static! { static ref TESTING_INVALID_CODES: [Vec; 6] = [ @@ -120,23 +120,13 @@ mod test { }); // code A calls code B. - let pushdata = rand_bytes(8); - let code_a = bytecode! { - // populate memory in A's context. - PUSH8(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call ADDR_B. - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH32(call_data_length) // argsLength - PUSH32(call_data_offset) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata: rand_bytes(32), + call_data_length, + call_data_offset, + ..MockCallBytecodeParams::default() + }); let ctx = TestContext::<3, 1>::new( None, diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs index 65e894008a..cf6bc9638c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs @@ -134,10 +134,11 @@ mod tests { use eth_types::{ bytecode, evm_types::{GasCost, OpcodeId}, - Bytecode, ToWord, U256, + Bytecode, U256, }; use mock::{ - eth, test_ctx::helpers::account_0_code_account_1_no_code, TestContext, MOCK_ACCOUNTS, + eth, generate_mock_call_bytecode, test_ctx::helpers::account_0_code_account_1_no_code, + MockCallBytecodeParams, TestContext, MOCK_ACCOUNTS, }; #[test] @@ -202,26 +203,17 @@ mod tests { // code B gets called by code A, so the call is an internal call. let code_b = testing_data.bytecode.clone(); - let gas_cost_b = testing_data.gas_cost; - - // Code A calls code B. - let code_a = bytecode! { - // populate memory in A's context. - PUSH8(U256::from_big_endian(&rand_bytes(8))) - PUSH1(0x00) // offset - MSTORE - // call ADDR_B. - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH32(0x00) // argsLength - PUSH32(0x20) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - // Decrease expected gas cost (by 1) to trigger out of gas error. - PUSH32(gas_cost_b - 1) // gas - CALL - STOP - }; + + // code A calls code B. + // Decrease expected gas cost (by 1) to trigger out of gas error. + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata: rand_bytes(32), + call_data_length: 0x00usize, + call_data_offset: 0x20usize, + gas: testing_data.gas_cost - 1, + ..MockCallBytecodeParams::default() + }); let ctx = TestContext::<3, 1>::new( None, diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs index 53481febb6..0228957a15 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs @@ -256,9 +256,11 @@ mod test { use eth_types::{ bytecode, evm_types::{GasCost, OpcodeId}, - Bytecode, ToWord, U256, + Bytecode, U256, + }; + use mock::{ + eth, generate_mock_call_bytecode, MockCallBytecodeParams, TestContext, MOCK_ACCOUNTS, }; - use mock::{eth, TestContext, MOCK_ACCOUNTS}; use std::cmp::max; const TESTING_STORAGE_KEY: U256 = U256([0, 0, 0, 0x030201]); @@ -491,24 +493,18 @@ mod test { let code_b = testing_data.bytecode.clone(); let gas_cost_b = testing_data.gas_cost; - // Code A calls code B. - let code_a = bytecode! { - // populate memory in A's context. - PUSH8(U256::from_big_endian(&rand_bytes(8))) - PUSH1(0x00) // offset - MSTORE - // call ADDR_B. - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH32(0x00) // argsLength - PUSH32(0x20) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - // Decrease expected gas cost (by 1) to trigger out of gas error. - PUSH32(gas_cost_b - 1) // gas - CALL - STOP - }; + // code A calls code B. + // Decrease expected gas cost (by 1) to trigger out of gas error. + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata: rand_bytes(32), + return_data_offset: 0x00usize, + return_data_size: 0x00usize, + call_data_length: 0x20usize, + call_data_offset: 0x10usize, + gas: gas_cost_b - 1, + ..MockCallBytecodeParams::default() + }); let ctx = TestContext::<3, 1>::new( None, diff --git a/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs b/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs index e173b844a8..88c56218e7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs @@ -204,9 +204,7 @@ mod test { if is_root { code_b.append(&bytecode! { - PUSH32(return_data_size) - PUSH32(return_data_offset) - RETURN + .return_bytecode(return_data_offset, return_data_size) STOP }); } else { @@ -216,9 +214,7 @@ mod test { PUSH32(dest_offset) // memory offset RETURNDATACOPY // end for internal - PUSH32(return_data_size) - PUSH32(return_data_offset) - RETURN + .return_bytecode(return_data_offset, return_data_size) STOP }); } @@ -246,9 +242,7 @@ mod test { }); } else { code_a.append(&bytecode! { - PUSH32(return_data_size) - PUSH32(return_data_offset) - RETURN + .return_bytecode(return_data_offset, return_data_size) }); } diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs index 2dbace9da6..3d1c99a690 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs @@ -145,8 +145,11 @@ impl ExecutionGadget for ExtcodesizeGadget { #[cfg(test)] mod test { use crate::{evm_circuit::test::rand_bytes, test_util::CircuitTestBuilder}; - use eth_types::{bytecode, geth_types::Account, Bytecode, ToWord, Word}; - use mock::{TestContext, MOCK_1_ETH, MOCK_ACCOUNTS, MOCK_CODES}; + use eth_types::{bytecode, geth_types::Account, Bytecode, ToWord}; + use mock::{ + generate_mock_call_bytecode, MockCallBytecodeParams, TestContext, MOCK_1_ETH, + MOCK_ACCOUNTS, MOCK_CODES, + }; #[test] fn test_extcodesize_gadget_simple() { @@ -199,29 +202,19 @@ mod test { }); // code A calls code B. - let pushdata = rand_bytes(8); - let bytecode_a = bytecode! { - // populate memory in A's context. - PUSH8(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call ADDR_B. - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH32(0xff) // argsLength - PUSH32(0x1010) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata: rand_bytes(32), + call_data_length: 0xffusize, + call_data_offset: 0x1010usize, + ..MockCallBytecodeParams::default() + }); let ctx = TestContext::<4, 1>::new( None, |accs| { accs[0].address(addr_b).code(bytecode_b); - accs[1].address(addr_a).code(bytecode_a); + accs[1].address(addr_a).code(code_a); // Set code if account exists. if account_exists { accs[2].address(account.address).code(account.code.clone()); diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs index 4a8a91e957..706be81dea 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs @@ -269,8 +269,8 @@ impl ExecutionGadget for ReturnDataCopyGadget { mod test { use crate::{evm_circuit::test::rand_bytes, test_util::CircuitTestBuilder}; use bus_mapping::circuit_input_builder::CircuitsParams; - use eth_types::{bytecode, ToWord, Word}; - use mock::test_ctx::TestContext; + use eth_types::{bytecode, Word}; + use mock::{generate_mock_call_bytecode, test_ctx::TestContext, MockCallBytecodeParams}; fn test_ok_internal( return_data_offset: usize, @@ -281,37 +281,28 @@ mod test { ) { let (addr_a, addr_b) = (mock::MOCK_ACCOUNTS[0], mock::MOCK_ACCOUNTS[1]); - let pushdata = rand_bytes(32); let return_offset = std::cmp::max((return_data_offset + return_data_size) as i64 - 32, 0) as usize; let code_b = bytecode! { - PUSH32(Word::from_big_endian(&pushdata)) - PUSH32(return_offset) - MSTORE - - PUSH32(return_data_size) - PUSH32(return_data_offset) - RETURN + .mstore(return_offset, Word::from_big_endian(&rand_bytes(32))) + .return_bytecode(return_data_offset, return_data_size) STOP }; // code A calls code B. - let code_a = bytecode! { - // call ADDR_B. - PUSH32(return_data_size) // retLength - PUSH32(return_data_offset) // retOffset - PUSH1(0x00) // argsLength - PUSH1(0x00) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL + let instruction = bytecode! { PUSH32(size) // size PUSH32(offset) // offset PUSH32(dest_offset) // dest_offset RETURNDATACOPY - STOP }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + return_data_offset, + return_data_size, + instructions_after_call: instruction, + ..MockCallBytecodeParams::default() + }); let ctx = TestContext::<3, 1>::new( None, diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs index b7e1d41cd5..766e8628ac 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs @@ -87,38 +87,28 @@ impl ExecutionGadget for ReturnDataSizeGadget { #[cfg(test)] mod test { use crate::{evm_circuit::test::rand_bytes, test_util::CircuitTestBuilder}; - use eth_types::{bytecode, ToWord, Word}; - use mock::test_ctx::TestContext; + use eth_types::{bytecode, Word}; + use mock::{generate_mock_call_bytecode, test_ctx::TestContext, MockCallBytecodeParams}; fn test_ok_internal(return_data_offset: usize, return_data_size: usize) { let (addr_a, addr_b) = (mock::MOCK_ACCOUNTS[0], mock::MOCK_ACCOUNTS[1]); - let pushdata = rand_bytes(32); let code_b = bytecode! { - PUSH32(Word::from_big_endian(&pushdata)) - PUSH1(0) - MSTORE - - PUSH32(return_data_size) - PUSH1(return_data_offset) - RETURN + .mstore(0, Word::from_big_endian(&rand_bytes(32))) + .return_bytecode(return_data_offset, return_data_size) STOP }; - // code A calls code B. - let code_a = bytecode! { - // call ADDR_B. - PUSH32(return_data_size) // retLength - PUSH1(return_data_offset) // retOffset - PUSH1(0x00) // argsLength - PUSH1(0x00) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL + let instruction = bytecode! { RETURNDATASIZE - STOP }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + return_data_offset, + return_data_size, + instructions_after_call: instruction, + ..MockCallBytecodeParams::default() + }); let ctx = TestContext::<3, 1>::new( None, From 896cd94e9c2347e83b22b07b9107d8a22fa48442 Mon Sep 17 00:00:00 2001 From: Thomas Pan <43927782+thomaspanf@users.noreply.github.com> Date: Thu, 13 Apr 2023 04:19:29 -0700 Subject: [PATCH 005/102] Fix `redundant constraint in StateCircuit` (#1339) ### Description Refer to comment in [#1161](https://github.com/privacy-scaling-explorations/zkevm-circuits/pull/1161#discussion_r1110022144) ### Issue Link [#1308](https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1308) ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### This PR contains: - Deleted [L401-402](https://github.com/privacy-scaling-explorations/zkevm-circuits/blob/7e9603a28a818819c071c81fd2f4f6b58737dea6/zkevm-circuits/src/state_circuit/constraint_builder.rs#L402) in StateCircuit --- zkevm-circuits/src/state_circuit/constraint_builder.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/zkevm-circuits/src/state_circuit/constraint_builder.rs b/zkevm-circuits/src/state_circuit/constraint_builder.rs index 947c6e21c9..6fbb1dc973 100644 --- a/zkevm-circuits/src/state_circuit/constraint_builder.rs +++ b/zkevm-circuits/src/state_circuit/constraint_builder.rs @@ -399,11 +399,6 @@ impl ConstraintBuilder { }); // 7.2. `initial value` is 0 self.require_zero("initial TxRefund value is 0", q.initial_value()); - // 7.3. First access for a set of all keys are 0 if READ - self.require_zero( - "first access for a set of all keys are 0 if READ", - q.first_access() * q.is_read() * q.value(), - ); } fn build_account_constraints(&mut self, q: &Queries) { From b476ef4b61ee13f6b812d9ea7534a32914e05076 Mon Sep 17 00:00:00 2001 From: Kimi Wu Date: Thu, 13 Apr 2023 19:47:30 +0800 Subject: [PATCH 006/102] feat/#1186 Unify restore_ctx and handle_return in bus_mapping (#1342) ### Description - unify handle_restore_context and gen_restore_context_ops ### Issue Link fix #1186 ### Type of change - [x] refactor (non-breaking change which adds functionality) ### Contents - merge `gen_restore_context_ops` into `handle_restore_context` --- .../circuit_input_builder/input_state_ref.rs | 147 +++++++----------- bus-mapping/src/evm/opcodes.rs | 14 +- bus-mapping/src/evm/opcodes/callop.rs | 4 +- bus-mapping/src/evm/opcodes/create.rs | 2 +- .../src/evm/opcodes/error_invalid_jump.rs | 5 +- bus-mapping/src/evm/opcodes/error_oog_call.rs | 3 +- bus-mapping/src/evm/opcodes/error_oog_exp.rs | 4 +- bus-mapping/src/evm/opcodes/error_oog_log.rs | 5 +- .../src/evm/opcodes/error_oog_sload_sstore.rs | 4 +- .../opcodes/error_return_data_outofbound.rs | 6 +- bus-mapping/src/evm/opcodes/error_simple.rs | 5 +- .../src/evm/opcodes/error_write_protection.rs | 5 +- bus-mapping/src/evm/opcodes/return_revert.rs | 4 +- bus-mapping/src/evm/opcodes/stop.rs | 11 +- 14 files changed, 78 insertions(+), 141 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index 9f13cb56e7..9258676eab 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -901,9 +901,19 @@ impl<'a> CircuitInputStateRef<'a> { } } - /// Handle a return step caused by any opcode that causes a return to the + /// Handle a restore and a return step caused by any opcode that causes a return to the /// previous call context. - pub fn handle_return(&mut self, step: &GethExecStep) -> Result<(), Error> { + pub fn handle_return( + &mut self, + exec_step: &mut ExecStep, + geth_steps: &[GethExecStep], + need_restore: bool, + ) -> Result<(), Error> { + if need_restore { + self.handle_restore_context(exec_step, geth_steps)?; + } + + let step = &geth_steps[0]; // handle return_data let (return_data_offset, return_data_length) = { if !self.call()?.is_root { @@ -986,15 +996,46 @@ impl<'a> CircuitInputStateRef<'a> { } /// Bus mapping for the RestoreContextGadget as used in RETURN. - // TODO: unify this with restore context bus mapping for STOP. - // TODO: unify this with the `handle return function above.` pub fn handle_restore_context( &mut self, - steps: &[GethExecStep], exec_step: &mut ExecStep, + steps: &[GethExecStep], ) -> Result<(), Error> { let call = self.call()?.clone(); + let geth_step = steps + .get(0) + .ok_or(Error::InternalError("invalid index 0"))?; + let is_return_revert = geth_step.op == OpcodeId::REVERT || geth_step.op == OpcodeId::RETURN; + + if !is_return_revert && !call.is_success { + // add call failure ops for exception cases + self.call_context_read( + exec_step, + call.call_id, + CallContextField::IsSuccess, + 0u64.into(), + ); + + // Even call.rw_counter_end_of_reversion is zero for now, it will set in + // set_value_ops_call_context_rwc_eor later + // if call fails, no matter root or internal, read RwCounterEndOfReversion for + // circuit constraint. + self.call_context_read( + exec_step, + call.call_id, + CallContextField::RwCounterEndOfReversion, + call.rw_counter_end_of_reversion.into(), + ); + + if call.is_root { + return Ok(()); + } + } + let caller = self.caller()?.clone(); + let geth_step_next = steps + .get(1) + .ok_or(Error::InternalError("invalid index 1"))?; self.call_context_read( exec_step, call.call_id, @@ -1002,9 +1043,6 @@ impl<'a> CircuitInputStateRef<'a> { caller.call_id.into(), ); - let geth_step = &steps[0]; - let geth_step_next = &steps[1]; - let [last_callee_return_data_offset, last_callee_return_data_length] = match geth_step.op { OpcodeId::STOP => [Word::zero(); 2], OpcodeId::REVERT | OpcodeId::RETURN => { @@ -1018,7 +1056,7 @@ impl<'a> CircuitInputStateRef<'a> { [offset, length] } } - _ => unreachable!(), + _ => [Word::zero(), Word::zero()], }; let curr_memory_word_size = (exec_step.memory_size as u64) / 32; @@ -1041,7 +1079,11 @@ impl<'a> CircuitInputStateRef<'a> { }; let gas_refund = geth_step.gas.0 - memory_expansion_gas_cost - code_deposit_cost; - let caller_gas_left = geth_step_next.gas.0 - gas_refund; + let caller_gas_left = if is_return_revert || call.is_success { + geth_step_next.gas.0 - gas_refund + } else { + geth_step_next.gas.0 + }; for (field, value) in [ (CallContextField::IsRoot, (caller.is_root as u64).into()), @@ -1306,89 +1348,4 @@ impl<'a> CircuitInputStateRef<'a> { } Ok(()) } - - /// gen bus mapping operations for context restore purpose - pub(crate) fn gen_restore_context_ops( - &mut self, - exec_step: &mut ExecStep, - geth_steps: &[GethExecStep], - ) -> Result<(), Error> { - let geth_step = &geth_steps[0]; - let call = self.call()?.clone(); - if !call.is_success { - // add call failure ops for exception cases - self.call_context_read( - exec_step, - call.call_id, - CallContextField::IsSuccess, - 0u64.into(), - ); - - // Even call.rw_counter_end_of_reversion is zero for now, it will set in - // set_value_ops_call_context_rwc_eor later - // if call fails, no matter root or internal, read RwCounterEndOfReversion for - // circuit constraint. - self.call_context_read( - exec_step, - call.call_id, - CallContextField::RwCounterEndOfReversion, - call.rw_counter_end_of_reversion.into(), - ); - - if call.is_root { - return Ok(()); - } - } - - let caller = self.caller()?.clone(); - self.call_context_read( - exec_step, - call.call_id, - CallContextField::CallerId, - caller.call_id.into(), - ); - - let geth_step_next = &geth_steps[1]; - let caller_ctx = self.caller_ctx()?; - let caller_gas_left = if call.is_success { - geth_step_next.gas.0 - geth_step.gas.0 - } else { - geth_step_next.gas.0 - }; - - for (field, value) in [ - (CallContextField::IsRoot, (caller.is_root as u64).into()), - ( - CallContextField::IsCreate, - (caller.is_create() as u64).into(), - ), - (CallContextField::CodeHash, caller.code_hash.to_word()), - (CallContextField::ProgramCounter, geth_step_next.pc.0.into()), - ( - CallContextField::StackPointer, - geth_step_next.stack.stack_pointer().0.into(), - ), - (CallContextField::GasLeft, caller_gas_left.into()), - ( - CallContextField::MemorySize, - caller_ctx.memory.word_size().into(), - ), - ( - CallContextField::ReversibleWriteCounter, - self.caller_ctx()?.reversible_write_counter.into(), - ), - ] { - self.call_context_read(exec_step, caller.call_id, field, value); - } - - for (field, value) in [ - (CallContextField::LastCalleeId, call.call_id.into()), - (CallContextField::LastCalleeReturnDataOffset, 0.into()), - (CallContextField::LastCalleeReturnDataLength, 0.into()), - ] { - self.call_context_write(exec_step, caller.call_id, field, value); - } - - Ok(()) - } } diff --git a/bus-mapping/src/evm/opcodes.rs b/bus-mapping/src/evm/opcodes.rs index 0229726412..8e558fb189 100644 --- a/bus-mapping/src/evm/opcodes.rs +++ b/bus-mapping/src/evm/opcodes.rs @@ -331,17 +331,19 @@ pub fn gen_associated_ops( if let Some(fn_gen_error_ops) = fn_gen_error_state_associated_ops(&exec_error) { return fn_gen_error_ops(state, geth_steps); } else { + // For exceptions that fail to enter next call context, we need + // to restore call context of current caller + let mut need_restore = true; + // For exceptions that already enter next call context, but fail immediately // (e.g. Depth, InsufficientBalance), we still need to parse the call. if geth_step.op.is_call_or_create() { let call = state.parse_call(geth_step)?; state.push_call(call); - // For exceptions that fail to enter next call context, we need - // to restore call context of current caller - } else { - state.gen_restore_context_ops(&mut exec_step, geth_steps)?; + need_restore = false; } - state.handle_return(geth_step)?; + + state.handle_return(&mut exec_step, geth_steps, need_restore)?; return Ok(vec![exec_step]); } } @@ -701,6 +703,6 @@ fn dummy_gen_selfdestruct_ops( state.sdb.destruct_account(sender); } - state.handle_return(geth_step)?; + state.handle_return(&mut exec_step, geth_steps, false)?; Ok(vec![exec_step]) } diff --git a/bus-mapping/src/evm/opcodes/callop.rs b/bus-mapping/src/evm/opcodes/callop.rs index db6e6b8c4a..d080e96fae 100644 --- a/bus-mapping/src/evm/opcodes/callop.rs +++ b/bus-mapping/src/evm/opcodes/callop.rs @@ -229,7 +229,7 @@ impl Opcode for CallOpcode { ] { state.call_context_write(&mut exec_step, current_call.call_id, field, value); } - state.handle_return(geth_step)?; + state.handle_return(&mut exec_step, geth_steps, false)?; Ok(vec![exec_step]) } // 3. Call to account with non-empty code. @@ -306,7 +306,7 @@ impl Opcode for CallOpcode { ] { state.call_context_write(&mut exec_step, current_call.call_id, field, value); } - state.handle_return(geth_step)?; + state.handle_return(&mut exec_step, geth_steps, false)?; Ok(vec![exec_step]) } // } diff --git a/bus-mapping/src/evm/opcodes/create.rs b/bus-mapping/src/evm/opcodes/create.rs index dff4bd2f81..d40fa678d3 100644 --- a/bus-mapping/src/evm/opcodes/create.rs +++ b/bus-mapping/src/evm/opcodes/create.rs @@ -176,7 +176,7 @@ impl Opcode for DummyCreate { if call.code_hash == CodeDB::empty_code_hash() { // 1. Create with empty initcode. - state.handle_return(geth_step)?; + state.handle_return(&mut exec_step, geth_steps, false)?; Ok(vec![exec_step]) } else { // 2. Create with non-empty initcode. diff --git a/bus-mapping/src/evm/opcodes/error_invalid_jump.rs b/bus-mapping/src/evm/opcodes/error_invalid_jump.rs index e9d202eb60..0e72a9b949 100644 --- a/bus-mapping/src/evm/opcodes/error_invalid_jump.rs +++ b/bus-mapping/src/evm/opcodes/error_invalid_jump.rs @@ -40,10 +40,9 @@ impl Opcode for InvalidJump { condition, )?; } - // `IsSuccess` call context operation is added in gen_restore_context_ops - state.gen_restore_context_ops(&mut exec_step, geth_steps)?; - state.handle_return(geth_step)?; + // `IsSuccess` call context operation is added in handle_return + state.handle_return(&mut exec_step, geth_steps, true)?; Ok(vec![exec_step]) } } diff --git a/bus-mapping/src/evm/opcodes/error_oog_call.rs b/bus-mapping/src/evm/opcodes/error_oog_call.rs index 706a71504c..a46423f097 100644 --- a/bus-mapping/src/evm/opcodes/error_oog_call.rs +++ b/bus-mapping/src/evm/opcodes/error_oog_call.rs @@ -90,8 +90,7 @@ impl Opcode for OOGCall { }, ); - state.gen_restore_context_ops(&mut exec_step, geth_steps)?; - state.handle_return(geth_step)?; + state.handle_return(&mut exec_step, geth_steps, true)?; Ok(vec![exec_step]) } } diff --git a/bus-mapping/src/evm/opcodes/error_oog_exp.rs b/bus-mapping/src/evm/opcodes/error_oog_exp.rs index 657c2f9c6d..a0d7f5bdc2 100644 --- a/bus-mapping/src/evm/opcodes/error_oog_exp.rs +++ b/bus-mapping/src/evm/opcodes/error_oog_exp.rs @@ -30,9 +30,7 @@ impl Opcode for OOGExp { )?; } - state.gen_restore_context_ops(&mut exec_step, geth_steps)?; - state.handle_return(geth_step)?; - + state.handle_return(&mut exec_step, geth_steps, true)?; Ok(vec![exec_step]) } } diff --git a/bus-mapping/src/evm/opcodes/error_oog_log.rs b/bus-mapping/src/evm/opcodes/error_oog_log.rs index a65fdd103b..cad2fcfa9e 100644 --- a/bus-mapping/src/evm/opcodes/error_oog_log.rs +++ b/bus-mapping/src/evm/opcodes/error_oog_log.rs @@ -43,9 +43,8 @@ impl Opcode for ErrorOOGLog { CallContextField::IsStatic, Word::from(state.call()?.is_static as u8), ); - // common error handling - state.gen_restore_context_ops(&mut exec_step, geth_steps)?; - state.handle_return(geth_step)?; + + state.handle_return(&mut exec_step, geth_steps, true)?; Ok(vec![exec_step]) } } diff --git a/bus-mapping/src/evm/opcodes/error_oog_sload_sstore.rs b/bus-mapping/src/evm/opcodes/error_oog_sload_sstore.rs index cd35a07370..6fbb24b83a 100644 --- a/bus-mapping/src/evm/opcodes/error_oog_sload_sstore.rs +++ b/bus-mapping/src/evm/opcodes/error_oog_sload_sstore.rs @@ -89,9 +89,7 @@ impl Opcode for OOGSloadSstore { ); } - state.gen_restore_context_ops(&mut exec_step, geth_steps)?; - state.handle_return(geth_step)?; - + state.handle_return(&mut exec_step, geth_steps, true)?; Ok(vec![exec_step]) } } diff --git a/bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs b/bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs index 5fa9d1c309..e2479924d5 100644 --- a/bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs +++ b/bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs @@ -68,10 +68,8 @@ impl Opcode for ErrorReturnDataOutOfBound { return_data.len().into(), ); - // `IsSuccess` call context operation is added in gen_restore_context_ops - - state.gen_restore_context_ops(&mut exec_step, geth_steps)?; - state.handle_return(geth_step)?; + // `IsSuccess` call context operation is added in handle_return + state.handle_return(&mut exec_step, geth_steps, true)?; Ok(vec![exec_step]) } } diff --git a/bus-mapping/src/evm/opcodes/error_simple.rs b/bus-mapping/src/evm/opcodes/error_simple.rs index 1c1840d94b..c27dd06e33 100644 --- a/bus-mapping/src/evm/opcodes/error_simple.rs +++ b/bus-mapping/src/evm/opcodes/error_simple.rs @@ -22,10 +22,7 @@ impl Opcode for ErrorSimple { let next_step = geth_steps.get(1); exec_step.error = state.get_step_err(geth_step, next_step).unwrap(); - // handles all required steps - state.gen_restore_context_ops(&mut exec_step, geth_steps)?; - state.handle_return(geth_step)?; - + state.handle_return(&mut exec_step, geth_steps, true)?; Ok(vec![exec_step]) } } diff --git a/bus-mapping/src/evm/opcodes/error_write_protection.rs b/bus-mapping/src/evm/opcodes/error_write_protection.rs index a80e795b71..58c4f937de 100644 --- a/bus-mapping/src/evm/opcodes/error_write_protection.rs +++ b/bus-mapping/src/evm/opcodes/error_write_protection.rs @@ -62,9 +62,8 @@ impl Opcode for ErrorWriteProtection { (current_call.is_static as u64).into(), ); - // `IsSuccess` call context operation is added in gen_restore_context_ops - state.gen_restore_context_ops(&mut exec_step, geth_steps)?; - state.handle_return(geth_step)?; + // `IsSuccess` call context operation is added in handle_return + state.handle_return(&mut exec_step, geth_steps, true)?; Ok(vec![exec_step]) } } diff --git a/bus-mapping/src/evm/opcodes/return_revert.rs b/bus-mapping/src/evm/opcodes/return_revert.rs index 8c56064753..d3bd76fd2b 100644 --- a/bus-mapping/src/evm/opcodes/return_revert.rs +++ b/bus-mapping/src/evm/opcodes/return_revert.rs @@ -92,7 +92,7 @@ impl Opcode for ReturnRevert { // Case C in the specs. if !call.is_root { - state.handle_restore_context(steps, &mut exec_step)?; + state.handle_restore_context(&mut exec_step, steps)?; } // Case D in the specs. @@ -132,7 +132,7 @@ impl Opcode for ReturnRevert { } } - state.handle_return(step)?; + state.handle_return(&mut exec_step, steps, false)?; Ok(vec![exec_step]) } } diff --git a/bus-mapping/src/evm/opcodes/stop.rs b/bus-mapping/src/evm/opcodes/stop.rs index 93f2db9fc2..4ee0b3f47b 100644 --- a/bus-mapping/src/evm/opcodes/stop.rs +++ b/bus-mapping/src/evm/opcodes/stop.rs @@ -32,16 +32,7 @@ impl Opcode for Stop { 1.into(), ); - if !call.is_root { - // The following part corresponds to - // Instruction.step_state_transition_to_restored_context - // in python spec, and should be reusable among all expected halting opcodes or - // exceptions. - state.gen_restore_context_ops(&mut exec_step, geth_steps)?; - } - - state.handle_return(geth_step)?; - + state.handle_return(&mut exec_step, geth_steps, !call.is_root)?; Ok(vec![exec_step]) } } From 8f4f55c1ed320fe6ca3da02c7469d2784377edbc Mon Sep 17 00:00:00 2001 From: Akase Cho Date: Fri, 14 Apr 2023 06:44:09 +0800 Subject: [PATCH 007/102] disable optimization for solc compiling (#1341) fix https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1302 --------- Co-authored-by: Zhang Zhuo --- testool/codehash.txt | 1204 +++++++++++++++++++-------------------- testool/src/compiler.rs | 206 +++++-- 2 files changed, 761 insertions(+), 649 deletions(-) diff --git a/testool/codehash.txt b/testool/codehash.txt index d52774dd98..233a3ad2d3 100644 --- a/testool/codehash.txt +++ b/testool/codehash.txt @@ -189,7 +189,7 @@ a6b511ce812a179b7a64838fbaa1d07cf7cd4b36c8060e086aa4b5fa61c971fd=600060006000600 f622260e13d7fabcc2cd9c1354d70e72614d8880f0c9682d07628c29b908e463=61600d600055630fffffff5600 d038887431975103a6ff47e75a1d183785b52fe006a23f264fc2eb621cff5b2f=600051506001600003506000515661600d60005500 3910e9d2cbc043a8ba787db1c0a21eb65944c7da49fc5485bdc90856d36e9c81=60006000600060006004356101000162010000f400 -a18f72995cc53877315840eb65f7906e0c90fddf4d49711297129d5539ce03de=600435600080600080846113885a03f45050 +a18f72995cc53877315840eb65f7906e0c90fddf4d49711297129d5539ce03de=6004356000600060006000846113885a03f45050 6648e38b61baede61a47f6b6fdd734b8dae0b2fd565c4b13caad748d3c77aa61=61600d60005560006010602002575b00 dfddcfaa0f3d8f89349db1aaa2ab93a46d95d27f80f9c11bfa55d98d52a9ef39=61600d60005560ff630fffffff5700 5f897f8795f7aaecc09acc9d1248777be536bed19a84da9fed831cfc1741b597=61600d6000556000630fffffff5700 @@ -384,838 +384,838 @@ ecc2da6d921e3a8add8be7f8e2edb8affa9362a00081d0fa10c3fcb93ad50390=73095e7baea6a6c 0f8768e84bd90b2a15fa1d47b16a20496ce88b55f6e2c461a38dcbb3aff56653=63deadbeef6000526101206000f300 529602fa473129c61090597d1c9cdc954defa61394356c24412d9b65df7591cf=600035ff00 9ee82de581ce9d8b59a47c812ff01adfff66aca971f144109aa5ec74b42d9a50=60016024351461001157600050610019565b61c0de612000525b60026024351461002b57600050610032565b6002612000525b6000604435146100445760005061004d565b61200051612040525b60016044351461005f57600050610071565b60a060020a6001026120005101612040525b60026044351461008357600050610095565b60fe60020a6001026120005101612040525b6003604435146100a7576000506100b9565b60ff60020a6001026120005101612040525b6004604435146100cb576000506100dd565b60a060020a6001026120005103612040525b67ff00ff00ff00ff006120205266ff00ff00ff00ff6120605260316004351461010857600050610139565b61200051316120205261204051316120605260016024351461012f57600061208052610138565b62010000612080525b5b603b6004351461014b5760005061017a565b612000513b61202052612040513b6120605260016024351461017257600061208052610179565b600f612080525b5b603c6004351461018c576000506101e0565b60206000612020612000513c60206000612060612040513c6001602435146101b9576000612080526101df565b7f63deadbeef6000526101206000f3000000000000000000000000000000000000612080525b5b603f600435146101f257600050610240565b612000513f61202052612040513f612060526001602435146102195760006120805261023f565b7f85ab232a015279867a1f5b5da4f9688c6c92e555c122e9147f9d13bc53c03e92612080525b5b60f160043514610252576000506102bb565b60206120206020612000600061200051611000f15060206120606020612000600061204051611000f1506001602435146102b0577f9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2612080526102ba565b63deadbeef612080525b5b60f2600435146102cd57600050610336565b60206120206020612000600061200051611000f25060206120606020612000600061204051611000f25060016024351461032b577f9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed261208052610335565b63deadbeef612080525b5b60f460043514610348576000506103ad565b6020612020602061200061200051611000f4506020612060602061200061204051611000f4506001602435146103a2577f9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2612080526103ac565b63deadbeef612080525b5b60fa600435146103bf57600050610424565b6020612020602061200061200051611000fa506020612060602061200061204051611000fa50600160243514610419577f9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed261208052610423565b63deadbeef612080525b5b60ff60043514610436576000506104b6565b61200051316120a052600060006020612000600062dead016310000000f150612000513161202052600060006020612040600062dead026310000000f150612000513161206052612020516120605103612060526120a0516120205103612020526001602435146104ad57611000612080526104b5565b611000612080525b5b61206051612020510360005561208051612020510360015560006101005500 -0e9c2dc682cf70a4bc15c56c064427939e0131445e20b4404363021ae9652610=fe -9a270b7cc69db5ebae71e25c626f1c262f9d6de5dc420a84bc7c80873af0984e=fe -2b43e66f7532c69d2c7c3bea96fd2de05c1d839322d155e3a537376d7e4c97e0=6220c0de803b80600080843c806000f3 -29e7cb59911b8f832e89bec6d412a599527b814628d898f6bdd863ff80e35f63=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f1811461015d5760f281146101715760f481146101855760fa81146101985761f1f181146101ab5761f2f181146101c15761f4f181146101d75761faf181146101ec5761f1f281146102015761f2f281146102175761f4f2811461022d5761faf281146102425761f1f481146102575761f2f4811461026d5761f4f481146102835761faf481146102985761f1fa81146102ad5761f2fa81146102c35761f4fa81146102d95761fafa81146102ee5760fd81146103035760fe81146103055760ff81146103075760f081146103095760f5811461032c5761f0f181146103525761f5f1811461037c5761f0f281146103a95761f5f281146103cc5761f0f481146103f25761f5f481146104145761f0fa81146104395761f5fa8114610462576460baccfa57811461048e5765bad0bad0bad06000526104a8565bfe5b602060008060008061ca115af195506104a8565b602060008060008061ca115af295506104a8565b6020600080600061ca115af495506104a8565b6020600080600061ca115afa95506104a8565b602060008060008063ca1100f15af195506104a8565b602060008060008063ca1100f15af295506104a8565b6020600080600063ca1100f15af495506104a8565b6020600080600063ca1100f15afa95506104a8565b602060008060008063ca1100f25af195506104a8565b602060008060008063ca1100f25af295506104a8565b6020600080600063ca1100f25af495506104a8565b6020600080600063ca1100f25afa95506104a8565b602060008060008063ca1100f45af195506104a8565b602060008060008063ca1100f45af295506104a8565b6020600080600063ca1100f45af495506104a8565b6020600080600063ca1100f45afa95506104a8565b602060008060008063ca1100fa5af195506104a8565b602060008060008063ca1100fa5af295506104a8565b6020600080600063ca1100fa5af495506104a8565b6020600080600063ca1100fa5afa95506104a8565bfe5bfe5bfe5b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6104a8565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6104a8565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506104a8565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506104a8565b8160008563c0dec0de3c81846000f094506020600080600080895af295506104a8565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506104a8565b8160008563c0dec0de3c81846000f0945060206000806000885af495506104a8565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506104a8565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506104a8565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506104a8565b6103ff6000526020600060206000806460baccfa575af195505b50846104b45760206000fd5b836104bf5760206000fd5b600051600055505050505050 -8362f328002b4d0c08e880edbc2133df809f450ed36f03185a99060b9498af41=fe -dfb3a38ca43d43a65edc3c3a0fd72cd14caac2ddc137b69acbb056f64a00aa13=602060008060008061ca115af160155760206000fd5b60206000f3 -fdcfd31543389df1a8b8bec4d90fd0ddcc4a817a631932e94529b11d53f8df17=602060008060008061ca115af260155760206000fd5b60206000f3 -65699b2d0e8558090352144d9310209295295547704451860855f4c230ce596e=6020600080600061ca115af460145760206000fd5b60206000f3 -e43e9d52cbc260ffe419a5c93a18852abe333e1bf102711765f13090f29793a2=6020600080600061ca115afa60145760206000fd5b60206000f3 -cbf22222a7bb92f681e16384d575b92e73420196573a32d298ba4475923e9e98=fe -0514a02fa4c5841a8341bd250fe42c5a340ea8830ded807baab6b37492d02139=fe +0e9c2dc682cf70a4bc15c56c064427939e0131445e20b4404363021ae9652610=fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 +9a270b7cc69db5ebae71e25c626f1c262f9d6de5dc420a84bc7c80873af0984e=fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 +2b43e66f7532c69d2c7c3bea96fd2de05c1d839322d155e3a537376d7e4c97e0=6220c0de803b8060006000843c806000f35050 +29e7cb59911b8f832e89bec6d412a599527b814628d898f6bdd863ff80e35f63=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101865760f2811461019c5760f481146101b25760fa81146101c65761f1f181146101da5761f2f181146101f25761f4f1811461020a5761faf181146102205761f1f281146102365761f2f2811461024e5761f4f281146102665761faf2811461027c5761f1f481146102925761f2f481146102aa5761f4f481146102c25761faf481146102d85761f1fa81146102ee5761f2fa81146103065761f4fa811461031e5761fafa81146103345760fd811461034a5760fe81146103c75760ff81146104465760f081146104c45760f581146104e75761f0f1811461050d5761f5f181146105395761f0f281146105685761f5f2811461058d5761f0f481146105b55761f5f481146105d85761f0fa81146105fe5761f5fa8114610628576460baccfa5781146106555765bad0bad0bad0600052610670565bfe7fdead60a700000000000000000000000000000000000000000000000000000000600052610670565b6020600060006000600061ca115af19550610670565b6020600060006000600061ca115af29550610670565b602060006000600061ca115af49550610670565b602060006000600061ca115afa9550610670565b6020600060006000600063ca1100f15af19550610670565b6020600060006000600063ca1100f15af29550610670565b602060006000600063ca1100f15af49550610670565b602060006000600063ca1100f15afa9550610670565b6020600060006000600063ca1100f25af19550610670565b6020600060006000600063ca1100f25af29550610670565b602060006000600063ca1100f25af49550610670565b602060006000600063ca1100f25afa9550610670565b6020600060006000600063ca1100f45af19550610670565b6020600060006000600063ca1100f45af29550610670565b602060006000600063ca1100f45af49550610670565b602060006000600063ca1100f45afa9550610670565b6020600060006000600063ca1100fa5af19550610670565b6020600060006000600063ca1100fa5af29550610670565b602060006000600063ca1100fa5af49550610670565b602060006000600063ca1100fa5afa9550610670565bfe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103c257640badbadbad6000525b610670565bfe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561044157640badbadbad6000525b610670565bfe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156104bf57640badbadbad6000525b610670565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c610670565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c610670565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af19550610670565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af19550610670565b8160008563c0dec0de3c81846000f0945060206000600060006000895af29550610670565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af29550610670565b8160008563c0dec0de3c81846000f094506020600060006000885af49550610670565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af49550610670565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa9550610670565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa9550610670565b6103ff600052602060006020600060006460baccfa575af195505b5084151561067e5760206000fd5b83151561068b5760206000fd5b600051600055505050505050 +8362f328002b4d0c08e880edbc2133df809f450ed36f03185a99060b9498af41=fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 +dfb3a38ca43d43a65edc3c3a0fd72cd14caac2ddc137b69acbb056f64a00aa13=6020600060006000600061ca115af1151560195760206000fd5b60206000f3 +fdcfd31543389df1a8b8bec4d90fd0ddcc4a817a631932e94529b11d53f8df17=6020600060006000600061ca115af2151560195760206000fd5b60206000f3 +65699b2d0e8558090352144d9310209295295547704451860855f4c230ce596e=602060006000600061ca115af4151560175760206000fd5b60206000f3 +e43e9d52cbc260ffe419a5c93a18852abe333e1bf102711765f13090f29793a2=602060006000600061ca115afa151560175760206000fd5b60206000f3 +cbf22222a7bb92f681e16384d575b92e73420196573a32d298ba4475923e9e98=fe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe +0514a02fa4c5841a8341bd250fe42c5a340ea8830ded807baab6b37492d02139=fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd 38f547750047a472fa72fec253a4527ebd73e74d1ef59d71ab51dff7714d7005=6000ff -20eab3c8d300ca0bc99f12bab2359d3afe554d389def84f35d804da88303ecbd=60003560008103600b57fe5b600181036000526020600060206000806460baccfa575af1602c5760206000fd5b60206000f3 -42f7c2f75c75cef03d21d28ea88ee056455a41df4fa69e84448ada32ee1e20cc=610200600080f050 -5049b9ef30dce1c4fc833042e5e868e76b8447d2a38c364ac574f3e5b8e94564=5a615a1701610200600080f550 +20eab3c8d300ca0bc99f12bab2359d3afe554d389def84f35d804da88303ecbd=6000356000811415603557fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af1151560595760206000fd5b60206000f350 +42f7c2f75c75cef03d21d28ea88ee056455a41df4fa69e84448ada32ee1e20cc=61020060006000f050 +5049b9ef30dce1c4fc833042e5e868e76b8447d2a38c364ac574f3e5b8e94564=5a615a170161020060006000f550 9a76f62b8b1305059c0392f4d8293bc5d6f13ff4a3502f35a56ffea9f3102e91=00 -c71639a1d42dc0079620a8748605a805df5009b435adcef233671749fcd6fea8=610100600061010060008061ca115af150 -cf2810c927b9404e13cfd3755b60e6da83a777019e9290ba13bc2ef72028c384=610100600061010060008061ca115af250 +c71639a1d42dc0079620a8748605a805df5009b435adcef233671749fcd6fea8=61010060006101006000600061ca115af150 +cf2810c927b9404e13cfd3755b60e6da83a777019e9290ba13bc2ef72028c384=61010060006101006000600061ca115af250 7965d59aacd6cb567c346703fe84168ca1247909772f914c9481348eecab24c3=6101006000610100600061ca115af450 caead2353c6dfe042005dcced75ef872d4485c09b0a608a0142f7e6617963e5f=6101006000610100600061ca115afa50 635416a136a2c77e605894a10cbb3034338efdc3261571136d4b5689c377b7a2=61b0005150 d5fa7be3053a269955f2681e3456d906ed87394a2a8493c729b3582b438c12b5=60ff61b00052 a340c6e10bcd05d0f73c7b697a98ed582f2244cb0c37315ec4743247e51c173b=60ff61b00053 0f86028bf04f9934739e785ea0362e83beb4eb2bf7e941deb606dcc2f571e38f=61beef60002050 -4c10255b7e0067acc2ebd06666664cbb0e06b57f5e2da8d7f9065c8b6dd44904=61ca11803b600080833c50 -430d28ac555e5377b78dcc35ef76ea915c1f1830b34cae9638b2b46836a41f9b=600061ea6060043562c0de00015b6001838303111560445760028284010460008060008060008686f1600081036033578194505b60018103603e578193505b5050600d565b81600055505050 +4c10255b7e0067acc2ebd06666664cbb0e06b57f5e2da8d7f9065c8b6dd44904=61ca11803b60006000833c50 +430d28ac555e5377b78dcc35ef76ea915c1f1830b34cae9638b2b46836a41f9b=600061ea6060043562c0de00015b60018383031115604957600282840104600060006000600060008686f160008114156036578194505b60018114156042578193505b50505b600d565b81600055505050 938ee3f4c10a7ca8880a8893537cad1a5c5be41c18cf679b56d84ff0a7c86ba9=6009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 230ad8b2bee2664f3917e0eaa4fb99565b9b2989a0f5cd7847a2fcdc576b7e69=6009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0c178b5973abc40e8a8e1e36c759cfbbcea1c5272ee5efafef30b2f4b258caa3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260010c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260010c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0c178b5973abc40e8a8e1e36c759cfbbcea1c5272ee5efafef30b2f4b258caa3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260010c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 44988850b8a12a167c5cd7dddcd014166d37ab13ebe839fad024b62de3e660cf=6009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 96475191b3bcb0ad37a3b6df38be56139deaec7e02f1487bad194953eca95d21=6009600860076006600560046003600260010c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe cb7adbe8f8ee805ca68468f69f10f910b3853a98df2bdf577927b75fb11285e7=6009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -e3e1455165b47b69c29d61a2bc5078d5ad4d65e92b9687cb7180a3574e37c24f=600035600081036046576009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +e3e1455165b47b69c29d61a2bc5078d5ad4d65e92b9687cb7180a3574e37c24f=60003560008114156047576009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 17685510e75e3f74b8218b94229451ec1cc228ca37654b9b4634355eae2dbf9c=6009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 23951503023e580b1117ac0898cfba8b28e874ff8ecbb10741a11fc490966c44=6009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d5f2777b29693306828cec239d9c18c0712efd524dc6f747104d87feb3448b21=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260010d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260010d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d5f2777b29693306828cec239d9c18c0712efd524dc6f747104d87feb3448b21=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260010d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 62a6f08909838c6f7fd571901020f12c41c6915b77466aa87049392d55708787=6009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 8225f662322132ba756ddf40b9d38ee77569900e50f6017356c85ecefda4f0a4=6009600860076006600560046003600260010d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe ab0505ea2db66ed1dcae4b3ca8c86eb81a6cd7263bc4dbd23019560079f9a2f9=6009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -1de16d5bf91595f686c8a3e0b6759cd058cc82e743b0ad4b43bd5aa97b767c88=600035600081036046576009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +1de16d5bf91595f686c8a3e0b6759cd058cc82e743b0ad4b43bd5aa97b767c88=60003560008114156047576009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1068a1249d4c3b6b6f83ec022b0b09aba43bbc01520e2c6b2b42a546625fa486=6009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 d92166b2a2f6ab44b2fc9f7c8e177c7a20b78ac7d0f1f7ca688883cb378c4c64=6009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -8eda3038d723b0f5c25b04f2fce101c2316df4c50ba5bd7741e70a044348f7be=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260010e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260010e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +8eda3038d723b0f5c25b04f2fce101c2316df4c50ba5bd7741e70a044348f7be=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260010e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 253155f71a6ed583e6b384069ad9fb1b6702e97a8b32df4b87224ca37c84f685=6009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b411b634893a0d8a4d864f6dc3fd63bf69d2094b74608861b86f17f3dc63a3d1=6009600860076006600560046003600260010e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 2af31abacbbeaaf462fe2936c4b2d05649426985fe42b4061019a912a0f797d8=6009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -6a0bd10d9b4b130170f5ddb04a7738b14aabe4c805af9235f51f5ec4267dd2cf=600035600081036046576009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +6a0bd10d9b4b130170f5ddb04a7738b14aabe4c805af9235f51f5ec4267dd2cf=60003560008114156047576009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 c907e58ddf59dde5cda116a73a3be28226593da0b0278cd5b7d675f646493eb9=6009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 139fa7c0b243adb5fd1ca31d3af7d2bee20772d5b2a603a763879b4c984c6084=6009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ee2b3952f8672b7367b2b1ed5b47135309c31ee656bc48b11259d3b5828e9f2e=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260010f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260010f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ee2b3952f8672b7367b2b1ed5b47135309c31ee656bc48b11259d3b5828e9f2e=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260010f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8fa57f0ab296fa45e253f78c45e7d71aae05d2959f1585a24cab0343397dc611=6009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 41e71afd58b254195323c77a3cf0c3025936553d7ebe1db40db2a235ae09e4d7=6009600860076006600560046003600260010f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 0ef59d8bebe83d676f9e04d12156ade7dca0289de969382f170e878c7ffa2a97=6009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -400fbe7e32c200832d7596b58ff78cbceaa998d7565891132f8718e82241f39b=600035600081036046576009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +400fbe7e32c200832d7596b58ff78cbceaa998d7565891132f8718e82241f39b=60003560008114156047576009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1cc9592eb090e413d93224c9c40e9f0ec4bdcbdcd87c909ffeb7e78469478ed1=6009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 30b094e2b26a74f73b5f9999c6334032fb40d213ac1a42e974305ee36fc3484f=6009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b2854feb50f32aaccfa575fb4860ccde6ff989d0ba1ebf559dcb47bd9a5bc0cd=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260011e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260011e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b2854feb50f32aaccfa575fb4860ccde6ff989d0ba1ebf559dcb47bd9a5bc0cd=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260011e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 568e661d7df1612a19ba92b59655ad16d37b5f892806110e9206106842850d29=6009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 343f9e016b3d1873b1eeab5bac585e76ecb5458c3e6329d9e78729b1a5e8239d=6009600860076006600560046003600260011e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c51830e3c8437a8e0fb86ae9650a05a5ed4806ad8ce7b6426fafefbfd638e618=6009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -da1e4c58298849b0870a90846bf251ee62076a1c96e882d90550d62c2cee6af5=600035600081036046576009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +da1e4c58298849b0870a90846bf251ee62076a1c96e882d90550d62c2cee6af5=60003560008114156047576009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 58200d9da216bae346a002e950da89f7c8f583330942315f4d033697e0eaf389=6009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 1160b9999f89fdb04e0c310ab5417e25b4a50326a37ce3d6669753c72a749164=6009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -983e12fd64a4c75ea68b3dd69813ee55ffa87f5d8d9e597d2d10572f9596c334=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260011f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260011f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +983e12fd64a4c75ea68b3dd69813ee55ffa87f5d8d9e597d2d10572f9596c334=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260011f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 b5e02815891113e58d0a6f40c1c09cfd3e2af3ed8ac1c2e14b6cd3b0ab98a6ae=6009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 44a28f59bab3e9db86d9f1a2039c2344dd275c39a183817bbb9b342963fc8853=6009600860076006600560046003600260011f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 389b491a506152871ab588c30fc27545526d502942ebf1f76b808d2ac84fc079=6009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -fb321121abdcb461309886fd0c9afa0bb484a27abd369aa6cc6131fe7fe51677=600035600081036046576009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +fb321121abdcb461309886fd0c9afa0bb484a27abd369aa6cc6131fe7fe51677=60003560008114156047576009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 82671344199c33734491b4e2824df44f9ed75b0feb1246d4507f12e59a297f0d=600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 b521eb06a22eb8bc3373ea257eaa896e1f7aada6b1bd5703706666d3c7270539=600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -59a1a02e81319c8c4fdf78bc0ef07495b2160978b45e0178a72a2ac3ee4aafb3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001217fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001217fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +59a1a02e81319c8c4fdf78bc0ef07495b2160978b45e0178a72a2ac3ee4aafb3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001217fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 812a84a0e6d3bf51bc645998f0f1c628964001222d7370ddafcefe0a88238afa=600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 1817666e09c78ce0915367cf498574c3ae5f6f5964a18a6c9bbc6794d32bce20=600960086007600660056004600360026001217fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 91dfdcb44d5446d5e14a976bb0b00a7e2082523eae4494a9e57261eec389b6e8=600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -ce6a46d3faa4f776895fc2dff6080147e39e15ce4cbe4d110fd61efd22c3d663=60003560008103604657600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +ce6a46d3faa4f776895fc2dff6080147e39e15ce4cbe4d110fd61efd22c3d663=6000356000811415604757600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 b777769be0e6d61f5de811b1f25d1421a2cef7a5e848906ff1e5187ff6a99713=600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e8a7f37f57061b04b44539079f0af364057ddf19662e6d0016f44e587315f6db=600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -760ff99e0c688e06674e4afedb6212ecf2b58480a41684749d0137376c2aaa41=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001227fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001227fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +760ff99e0c688e06674e4afedb6212ecf2b58480a41684749d0137376c2aaa41=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001227fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 ee15e8b1def627c248e0ef2b349e642c28930100a66719b4d9d3b59c32e8d2c6=600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c9ef430aa137465df086e05e6883183d69b4211322ebc5b3dfebc0ad5e60adc6=600960086007600660056004600360026001227fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c12e66e38eb2f29bce1281e9ba5cd1c7b57263a77426e15091292df57bd30ba7=600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8418ea603b4e88c12557e883203943437c425dea592d79c7a1e4f5afb07c7399=60003560008103604657600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8418ea603b4e88c12557e883203943437c425dea592d79c7a1e4f5afb07c7399=6000356000811415604757600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 3a071d7023fb441bccc3c6aee65e5ce05b2918d1eb4e7ec9b5e2f4dc2c401740=600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 71daa9e7174bf24991b7ce85ea872819e5f50753a06bcb9dca91922054124698=600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -89f20a0e69e5f391e03b60d27e751ee3fb3e46a210b55c1e2c6cc74d2ef3ca89=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001237fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001237fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +89f20a0e69e5f391e03b60d27e751ee3fb3e46a210b55c1e2c6cc74d2ef3ca89=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001237fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f2331e094cf1086abd868e108d1549172e7bb4dc30d51edba9b262a9060a4761=600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b9b145ac0daaf21ea5e83d3f7e8d0ec148136c453b220834f2cc7002b4bcc343=600960086007600660056004600360026001237fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe b15ddb47eb4585801737e561cc5d2caaa4ad359adf6ce6cb22b4f4e2b331daa7=600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -efbc58adac9e1d333512bcc22be5f575ca088dce0f47710671b465cd85068c7d=60003560008103604657600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +efbc58adac9e1d333512bcc22be5f575ca088dce0f47710671b465cd85068c7d=6000356000811415604757600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 b89d4effa036fdd9714ea8d2909ac77aacc158a9d5f733a49c90f00af95c7a40=600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 bf620126fdaa0bbd11bf7624530fe444f68eb0ca8511e41316cb8c119e05c292=600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -113ad2cfcf913857d0dc5bbaac973be86da8da32114708fd235aef697aff0e55=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001247fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001247fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +113ad2cfcf913857d0dc5bbaac973be86da8da32114708fd235aef697aff0e55=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001247fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f69e49d7e6b3de110b1be4e148e271e1b9ba7d061ce06a202f6353ec4690299a=600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b7dff3fc909477303c54bec6ed33be91b00b66f8c6ac80272cd379c3171b9b24=600960086007600660056004600360026001247fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe d80182d7a88eb5a2daf5b0ea6cd6a707a1633bc99ff96952c953c9df56d9a81e=600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -26b5bc19c87e4c5d225dd5e8bcec86089b8d177a4139c29050f87e7ca4eb2720=60003560008103604657600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +26b5bc19c87e4c5d225dd5e8bcec86089b8d177a4139c29050f87e7ca4eb2720=6000356000811415604757600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 07dba075729f7d3a9ef6119d5c6675eb56146597942582040e967c7390dde883=600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 bd9d506b7f4f2a50d532e0e83e5609b54dfce0d54a8c54c3a1c225d9b2783eb4=600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -3fe65acb20e830f3619ef0632503b60eca4336d71bc659ad0ad231da07e80652=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001257fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001257fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +3fe65acb20e830f3619ef0632503b60eca4336d71bc659ad0ad231da07e80652=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001257fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 060a850ac93dee7f0f676de2852fe8ffd2f198696fc61938ff14ca04c62eb50b=600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 54c5078af4523181c6ee17a52f63a18029faae11b06f7328da3618b34ae738eb=600960086007600660056004600360026001257fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 12562f84d5161185148e125f2ab2daebcfc5de79299459bfa6f1d56e2219644f=600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -eb53fe99ce99a4bb6770345142474aaf1a0cab1a7d647efc0d205796611c50c4=60003560008103604657600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +eb53fe99ce99a4bb6770345142474aaf1a0cab1a7d647efc0d205796611c50c4=6000356000811415604757600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 6306f54c0faccf8f2946b4527b8a760f5caf5734fb951557efdc7cc2b7265020=600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 dab38748f11aa52dc375f7c80dabb1f52c66ee8fd11eb77a8b170fc11e061df7=600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -547da97da2db8099372801d9957365e6abef034a61b062db00b448c1d72300fb=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001267fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001267fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +547da97da2db8099372801d9957365e6abef034a61b062db00b448c1d72300fb=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001267fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 05bb935133313a3a5e317736000032b833292e0569793a0976e7d08f6cc627e3=600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 e0565c2e19f768dc678aed3b504c568bf98a98e870942f4153ddea01d9b17f9a=600960086007600660056004600360026001267fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3ba1210d65ebd6e8c729050cd990472bae1d52e5ffc50ff724c8a474569c29cc=600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -ac14c89491ab4f9496852b6faab382ab873000a20dd939df3c754367a66754a4=60003560008103604657600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +ac14c89491ab4f9496852b6faab382ab873000a20dd939df3c754367a66754a4=6000356000811415604757600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 eef1a17bec5196611cef1df091a0a6dde2c5b11d6a6188e51f617f0eb2bd4362=600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f7061682ca29c7948fbc253ef98d164d3fc9adf4706e186df381154aeaf040d2=600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e8c24645ea676418428a4efcac2ad3daedf009e6a4279013c0fc44b01c0989d7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001277fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001277fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e8c24645ea676418428a4efcac2ad3daedf009e6a4279013c0fc44b01c0989d7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001277fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 317abde5a92153497b8bf486243c4656e43437380e6e3ad03ee7e170a989addc=600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 29fa741fc890c810301dc9c0e20eb8e2e5ce9662cabffd9e8e8667e400acbc1c=600960086007600660056004600360026001277fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f00036cdd965cfff85830d094bc0fbb3e0e9f9396cf456f5114555d6bf7a3d28=600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -18c2b63211ef4a0dff198473fca3cb1253b164fb917ae1cc27bf7432f877719a=60003560008103604657600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +18c2b63211ef4a0dff198473fca3cb1253b164fb917ae1cc27bf7432f877719a=6000356000811415604757600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 578ed7aea34fb9053bc80d93af61003d2ab5c2f9683f448d0b010d666e8646e4=600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 94b5d42885ee094de03227f6cf52c99df51f7e7108c3522167b18fe424da7f45=600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -242013a89507c05b17c04fad0c6a1fd52ec3fa384f40b395bd3681764cc8f4b5=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001287fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001287fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +242013a89507c05b17c04fad0c6a1fd52ec3fa384f40b395bd3681764cc8f4b5=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001287fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 1d739df75b88d7a314195f4f6c2f103966591fbc40af5d85ea7b260cc4521b39=600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4675b56405f82e43e19afe81bd3178b59679476fa47adc0fc1c0ef0668180933=600960086007600660056004600360026001287fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe d9e877924f288d2a84a86fafd7ca9b9cb75ba9c4eb501fcc9cf92f81c21387f5=600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -1561ca76178e8448f44830c669acf2e17d4dfb2946d78671f1ef5ef056a91236=60003560008103604657600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +1561ca76178e8448f44830c669acf2e17d4dfb2946d78671f1ef5ef056a91236=6000356000811415604757600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9845c3d252553432dc173193bfa650823b5beab40b61737394fc0d501f675ce1=600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 b5a60844fe55cc6a04b5a58c0dd0f7c96d6053a66bd6bd6b8f9c9ce3fe2c1b13=600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0ca96f543bb78527612ba046247c61bb79ac58caef9e0aa5cd2d9fbdebcfe084=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001297fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001297fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0ca96f543bb78527612ba046247c61bb79ac58caef9e0aa5cd2d9fbdebcfe084=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001297fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 923910e3d6e8be73445eb3f993ff3d52d4a9eb2ccfb110d7bcff3053d5f8a18b=600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 47459c3386e36a6463108e07ed3a84a93579094d7a6c45acf3b6c836c7fc1d93=600960086007600660056004600360026001297fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 51df9d18d6e18041e83f5814c0601a00925b8d4b1e66740d07cbcfb5cdd4e569=600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -e29cdda491ea2a40f56672b3d4dca382dc051fa751a9a8f945365cb9beb12c5b=60003560008103604657600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +e29cdda491ea2a40f56672b3d4dca382dc051fa751a9a8f945365cb9beb12c5b=6000356000811415604757600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1667790fc49892808e26dce42b9067024bdf7447c14be38fb4f0fe7affc70315=6009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 0e272b725152fa9efc4db1e64ea68d0d18409eb12a4b5b860e43ce7d2c73c763=6009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -f2c7922a8b3563bfe558a8f90297876c17a1aa7406ac289377f11116a5f25125=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +f2c7922a8b3563bfe558a8f90297876c17a1aa7406ac289377f11116a5f25125=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 2fed7310cc2695527528578e0627bcbe1b48027db89c32d9ec573296daf407e9=6009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4c7781b662b945645193487b17f7bf6547b9e7e68b9bee00333a79741d3bb7e5=6009600860076006600560046003600260012a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe e611756da0056f0b984c4171711eb0f66e4b424c8da0258c9a3a45844d8ba412=6009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -5fe2aedfa5a4f2007d352078679cf620e88aa4772dfa8039b45565b6ac331e45=600035600081036046576009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +5fe2aedfa5a4f2007d352078679cf620e88aa4772dfa8039b45565b6ac331e45=60003560008114156047576009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 0948b8c75705dfc2c5eb08854fdb967f3c2ba10b13cf9918586d3947e5a4dbc9=6009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 89190d44147f4de08c240cae6e964fb264d896bfb55b3144e29ce300fdc96f99=6009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -4600118ac1c8f2372c55101463872f47235d57258d4a4111fb5b52caf9326629=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +4600118ac1c8f2372c55101463872f47235d57258d4a4111fb5b52caf9326629=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f349b9de8a276965f5e10044c8216ea5a15357f1181d486ea43cabf4ec7b35f9=6009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 94bb4b7630e6236592eb2022c26af4348b5c4b2a6c70df6bfc4af5c9865f4b3b=6009600860076006600560046003600260012b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f998b8658be28a6457ea25769ba94ee4393d48201cb7227e55ff8748591a1188=6009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -b7d856c286c7e4524c27bef823fb2862ed08e5f782a4897d930e5e51d000f0ce=600035600081036046576009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +b7d856c286c7e4524c27bef823fb2862ed08e5f782a4897d930e5e51d000f0ce=60003560008114156047576009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d330bae48ebd477135f0170a55250b1ea41526c929f4656ec937096354570bfa=6009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f03e8fe17989acfc4a6767d5d181e6740e488f351c8805316480a128c6fc8554=6009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -570068bb31bf808d763a485c572af81549bd7ebf4fed4090529f430fc2bce49a=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +570068bb31bf808d763a485c572af81549bd7ebf4fed4090529f430fc2bce49a=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 3cc1dd35f1bf78480d13c4c894480977f2b300ca54f67ef06b5be08f35c0f4a3=6009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 95c308319e3d077daad87a4f138752a2797f30ac8d9ea936a9591519c336e490=6009600860076006600560046003600260012c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 1987e07f43cec087446d698e5300c17ecc08a957270483ab7bf61b3fd88a32ee=6009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -075a655ef405ee084855076ead77114ce16ba75534c41c2df8a227c2abc38cbe=600035600081036046576009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +075a655ef405ee084855076ead77114ce16ba75534c41c2df8a227c2abc38cbe=60003560008114156047576009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 6fc0db48d2bfe1a44a02cb9f2d5603ecc3ab98d5ca6869ee88880913bf165595=6009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 67af5a87f59b54b6495aebb08b1e00b70beb0a985639b252805902c91cf5b0da=6009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d0d4130baf835a9ac84c3046960fb2cbeac37445dbdda5c78dccd9c4487d4bc7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d0d4130baf835a9ac84c3046960fb2cbeac37445dbdda5c78dccd9c4487d4bc7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 709f4839fe8d0f0884a050d814b1d626a9f8d0567811d6739aa7076e428e3ed2=6009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 60146ee47fa94b62afd1de2aa8216652b9c4fca5de013945572c1ad7b8f7ab21=6009600860076006600560046003600260012d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe d1ad091324d6cafb3a6e7b965384d37f945563186e93ffb91b25803d8accde0d=6009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8737af588495dd726c53d35e0b7798a7ab27f475195d025ac44e2ed2e9f21788=600035600081036046576009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8737af588495dd726c53d35e0b7798a7ab27f475195d025ac44e2ed2e9f21788=60003560008114156047576009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 17435fc237350074a11f982c4c5076ae982d57dde6cc8cbdae863fe5c73170b0=6009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 78608b6aafca30a01a4e2d58553b28a8ec3a08360756a6867ed028f05d58543e=6009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -142ca2d74e56296478c5216fe33a961ad1f909940461e04549921c6baae0d310=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +142ca2d74e56296478c5216fe33a961ad1f909940461e04549921c6baae0d310=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 0c7f89070797590b8d871cd2718ddced23da1f6d9e2573d262df4ff0a0a0796d=6009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 5cc6b3c72dc49a11c01ba68ab3ca4811106946c2d4d346d537c287b96d5cadcf=6009600860076006600560046003600260012e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3a72c1e0c73c0237c7865cb94e391f7b51ffcacafc2d7fed601932b62baaf063=6009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -f86bf1c45ec93fa6ae2601ba8809f6b28166dfcbdd4ca89bfba5085553d5193d=600035600081036046576009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +f86bf1c45ec93fa6ae2601ba8809f6b28166dfcbdd4ca89bfba5085553d5193d=60003560008114156047576009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 414a2436837bfb656681f8d74b5e8cf83f54992a290da8f0b624cb5ea3caf7d3=6009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5d1bbe989d4ae4e0799b20fa98b23ef667b3a1e32452762bf4994b1019e2dd97=6009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -6623366f6cd4c7b146068162d28f663f041bc5c8b3339ce80cce22aa2f4ae91b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +6623366f6cd4c7b146068162d28f663f041bc5c8b3339ce80cce22aa2f4ae91b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 5365137e4bd42cb95f7f94b3863c699ef13eea46451482b07141ee2f45c29998=6009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3a265e96cc67edc9fd622e9c8f09c11fa540441babc2302c4d213941c4af6d1b=6009600860076006600560046003600260012f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 986b406a1b50d653ad5a07a8721472c38bfb52e3fe523866c11255875968e919=6009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -a88e183c05e66acfb9f4b0ab63d1fc7be8b983a7bf5b74cc42bee90d8f5438fc=600035600081036046576009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +a88e183c05e66acfb9f4b0ab63d1fc7be8b983a7bf5b74cc42bee90d8f5438fc=60003560008114156047576009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9a4714fbdf05813e64e03dbbed4687685e7d5b266a5a3b263166d96f05aedc17=600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 9c38f5b3aebf6c5d2ce8ceb966acb31ae10357ae88d33119516959187ed04c8e=600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -7cddaf41ea4d16170cf19089d3bc305dca174e2b1732dee4903af75bdbeb1b4c=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001497fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001497fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +7cddaf41ea4d16170cf19089d3bc305dca174e2b1732dee4903af75bdbeb1b4c=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001497fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 9d577cf94428220da28c0b8a41f410b522020d65b5c8e17d639008b8bee37baf=600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 a46a48acd0af205e877799d0c8d3dabf0ff925f3bbbee5d96fb194fe24b3bf82=600960086007600660056004600360026001497fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe bf15ee2119a8c776a780165974b8e644ec7fad1137b404e3ae11108add851b60=600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c1c3991aeac2c3773ca81ac2435e567107bb91dbfc19092841024a675db206dd=60003560008103604657600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c1c3991aeac2c3773ca81ac2435e567107bb91dbfc19092841024a675db206dd=6000356000811415604757600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 5f46643c97f2b24211b5a01eb1ec97abcd8e40357a4833880ba08936bd09f86b=6009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 d5bec6c1d856f60d273240f18376a09553c3b6c6e0b2e093ae2b86c9ede53840=6009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -805a168fe93920941a8de3eed871020a0cc71466afbfdbfebf23014a272f5096=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +805a168fe93920941a8de3eed871020a0cc71466afbfdbfebf23014a272f5096=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 1c772d49b2a475db9c074ff23856a86d2cbe0401d9d3662cf754e24744c65d10=6009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 581ed05876c14509f37fa1a0cdf5a1e086119926da143205885c5404ad708b20=6009600860076006600560046003600260014a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 1d716efaddb4f7e0ddefb5aa8cfb6ef8e92197310aa684e6604f1deacda59608=6009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -489a47f2e1cad1937a3d2716ae929cfce2c7427b5c5bab7721ab15c1c43bacd8=600035600081036046576009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +489a47f2e1cad1937a3d2716ae929cfce2c7427b5c5bab7721ab15c1c43bacd8=60003560008114156047576009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 0dced3fc01f029d892ea79b06296941552085cc39178218212ad9eced158c3bb=6009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a2418bc5f50747f3642827b929360935566ad83951d719eeab6f09a3405566c8=6009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b596be88d8632a3695fbf7d142d273f419a824262d2c33114aafa7321268cfeb=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b596be88d8632a3695fbf7d142d273f419a824262d2c33114aafa7321268cfeb=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 5bb542e49eefddf0e2198fc4a16a19b4bb813878d9641e1cf8b21e629c426d21=6009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 dc683cb5689109fc9b3a0f7d1b2ab96e45579ba9dab80fb8c1834607a92f9acf=6009600860076006600560046003600260014b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 5dee84479d79d9de0436622b99da00b0e821a3a366bbe1d90b2fbd2578305c7c=6009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -7194a6731850aa94e54ed64390205e64f2e9f7ec6939c2e468d1e6052fc9dd26=600035600081036046576009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +7194a6731850aa94e54ed64390205e64f2e9f7ec6939c2e468d1e6052fc9dd26=60003560008114156047576009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 dac03672fecbc895d39f416c3d5f9287013ac2a4ec104ac5d7916c7d113a8ac4=6009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 450c0f2b08d2613f867e46b74c279fc97f7445a71700ecf036118e8b64ac04f9=6009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b5e2b88ac45fff42d0a6cac5e73ece523a64eeda2c535c72ddd5a3b5b5df2df2=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b5e2b88ac45fff42d0a6cac5e73ece523a64eeda2c535c72ddd5a3b5b5df2df2=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 2113ad0b1d88921edae398c9debb061acc21db749476fcc7155d17fcbc766daa=6009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 2186b1dbb5db112a710d8ea1309ae6fe8421d09a11c159a1f314b270a3bb2003=6009600860076006600560046003600260014c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 449260e60e60bd8833468bd543e381951ef7246d547c3555306b8489f035080a=6009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c9a76debc6fd52dafce119b0d8b6a0579828992afa6c65ad579ebf05d954bbef=600035600081036046576009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c9a76debc6fd52dafce119b0d8b6a0579828992afa6c65ad579ebf05d954bbef=60003560008114156047576009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f78a0051f2cf054be150a84c71250a1b2d94c26b2910b9ed65c488f35752529c=6009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5545873eec9ee46ecc7c3c81b487ebdc6c82a079800571930878a60fc3d0f3ba=6009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ab05d4d536f135f8b1563f7dbfa5eaf895fee2c78317d78c0c4b3ff3de1b9457=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ab05d4d536f135f8b1563f7dbfa5eaf895fee2c78317d78c0c4b3ff3de1b9457=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 35537ac9b48fe5c3ab0a1786ab4fe1dcd4c5a486a205c4e2c2c1c7035a83aadb=6009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 bd0735179d1d2c7387f5da8032866aa13032c49ba14d4a93297d87b911169513=6009600860076006600560046003600260014d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe cc964f4714ba3ef4ed0875a122eee444ec057559bd5f82c7f7aee62f332f7e19=6009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -e6672f781e8b423031409c2541fc834d2f9c30781c3174774eee3634cbb102b4=600035600081036046576009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +e6672f781e8b423031409c2541fc834d2f9c30781c3174774eee3634cbb102b4=60003560008114156047576009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 ae779725a8c98b7e66d84c9d84d9ece6b29f197d3c73da4f8edcc3f0bb9cb2cd=6009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a61df624f6e8f13a390caba5e48e46833da498d66300d2a7edce56538ae76d5c=6009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c13d93fa7aeb19705ad16a112cd7adb75159db5519fe9106d2e3d3ae86098cd4=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c13d93fa7aeb19705ad16a112cd7adb75159db5519fe9106d2e3d3ae86098cd4=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 9d7b3eb3bc6c20059ca181d0ca7f23625b2d6140301a4a8fdde1d7118e848de4=6009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3b0476fdf948756ddd558634f40d1c232fb83eabc23a9cbe974c807ea212147e=6009600860076006600560046003600260014e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 247339d44499a3c740cef516958655a4d8bb7655059316275dfbef8d441b2087=6009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -e5561ec1d724fe56c53bfe7160e9fcf689df1ccf97606a35f6065cbd8f9d8f22=600035600081036046576009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +e5561ec1d724fe56c53bfe7160e9fcf689df1ccf97606a35f6065cbd8f9d8f22=60003560008114156047576009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 e8cd4486cb70670131d053f139904e3a60073d6dae6830523acee4c3f1ba5386=6009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 d55547540141b5c2474116865a25c2074b577a778273ab5da0e552ccf0cfaf02=6009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d2b888a1e4f0215babb30d4bde4cacbf0f10d774ad6eab3897d254ecce84dc4a=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d2b888a1e4f0215babb30d4bde4cacbf0f10d774ad6eab3897d254ecce84dc4a=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 86d603dda136eabedebae7b0c92e9ef908cdeae1a7c64b8ea9a1586e4322df90=6009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f4830420556f48087180be5a547eb617b02954cac5d0f32e1a4475061bc53dda=6009600860076006600560046003600260014f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 1095b336e60f4181c7fcf952c990e25c06bdbe0172bf9437b3de45697970afc0=6009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -11d7ebcaaf4190d5b14d989a7e81d0001ebcc03063d7c39a8d0259a96aeed61d=600035600081036046576009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +11d7ebcaaf4190d5b14d989a7e81d0001ebcc03063d7c39a8d0259a96aeed61d=60003560008114156047576009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1d37ad3ecba693e5c7bbb335635f6d523d8a62ece84d8342fa2618b95d1809aa=6009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 147dbb70dd39330bc7810fac0bdc7ebe79cbc820ecf63273a714a2479037f4ac=6009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0b17087362c519279c47d90ad072fd1313d3cf7e2cd5f38d6479769c36a082b7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260015c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260015c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0b17087362c519279c47d90ad072fd1313d3cf7e2cd5f38d6479769c36a082b7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260015c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 5bd1b9546aa94ebb8530c1751b31c48c7b52ddd6b79734be7846dd857de86546=6009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f70a86737a9ce9082b30da8f1a40ef6726d7bf11acf24fc7532a3997d972347d=6009600860076006600560046003600260015c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 14fdbc5e86fccbf2259ce355c990a53abf6f403986ee97062032787fbf2e5a67=6009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -bb2dbfd0fecf67b886c881eb40a3bf1b7e23e2d6dc1fb667ac03b2eede5fd249=600035600081036046576009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +bb2dbfd0fecf67b886c881eb40a3bf1b7e23e2d6dc1fb667ac03b2eede5fd249=60003560008114156047576009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 c8624036f56a51f08b2ffd35faf49529eca29e28af035b0ae0d50ed86db706c1=6009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a2e0374bc7857327c8ba35ffff2b5f76b4f3bd5d4c1c8eb1226e70e5a7a0471d=6009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -12c97dc5ea9b69cbc61eef6a65b2b1f5bc056aa512b6ef91b358c279ab15f60f=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260015d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260015d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +12c97dc5ea9b69cbc61eef6a65b2b1f5bc056aa512b6ef91b358c279ab15f60f=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260015d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 9387c7b6187f6901ff27d62c398a4b1b5c9127990050bf58eb58eb89fb1dbe90=6009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 9e8f7a4f1617ed590aaa165a5347da8947a15c535ef51e3b8e1a07c885cb3c2c=6009600860076006600560046003600260015d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe a8d2e6881ebbfcc1852e0c1f0765a3e056b190e1cb2136ed1573983702125a89=6009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -644f7c153874c905f89f6bff11a70de4244ce8657a1428e6d702b596516f473d=600035600081036046576009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +644f7c153874c905f89f6bff11a70de4244ce8657a1428e6d702b596516f473d=60003560008114156047576009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 a3e7bc89de3bc95768a31345a9b17dc068a21d0acfe2d0faa50bfee527abf1fe=6009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 522eb3957173b5fa70095ddefc445e52747ab61a57a6cb6ba69dcad3a8a61c23=6009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ec8cd5ae508c638841ef91c02728cd418d3328a77e0a3de8490c7c43e9fe2edf=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260015e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260015e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ec8cd5ae508c638841ef91c02728cd418d3328a77e0a3de8490c7c43e9fe2edf=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260015e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 ee4037bbe88c11fb2fd47a485b421fcb12ef6b6222eaaa5185f2fcf98aafa827=6009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 791540cfc11716b0091faa24e4bfbab6224a6fa7d15b46b9e7c312087fb471c3=6009600860076006600560046003600260015e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 8b60bdb6d569bc8c93db1524cf0c906e8b489e801f337865b4768cab3d02bfe8=6009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -2a7a2d436d5028b5cca65e6a4ddbe43e79d41bbe8b194946b650e8a7ae4a95f1=600035600081036046576009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +2a7a2d436d5028b5cca65e6a4ddbe43e79d41bbe8b194946b650e8a7ae4a95f1=60003560008114156047576009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 3985e89094ec6add1a5fec4e9028dc868618558120e379b9a32111d76abbb722=6009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f406f382d6365894d2e79e047bcc8318eb362b3009e0c24450fd6dc1ebc09802=6009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -cb90f8f8d1399f09cc59afb30b2e1d19656593f908a340811c22743c8ec06033=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260015f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260015f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +cb90f8f8d1399f09cc59afb30b2e1d19656593f908a340811c22743c8ec06033=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260015f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 18563cf49ecc84c88fb26dc80586b5505720918dda5d64886a0183843ed1b390=6009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 cee67c20632de89651377f47b8b4d63536aa1892d81cd153babfab74aef85556=6009600860076006600560046003600260015f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 9ad1f5391eadcbcb99b3de4ec3ac3fc692025d0068434f706b35245665db16ea=6009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -f7a8515356cea83f5aad1ef8aa7ec797a8595f81961c283df205f50388517961=600035600081036046576009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +f7a8515356cea83f5aad1ef8aa7ec797a8595f81961c283df205f50388517961=60003560008114156047576009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d1eab8fea44614eff5970e1e7261a183641d737cffd761337cf19e11a1b56b23=600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 edab2de8e06c42119704196b4143f60e32a0c6896327cf03d59eed9ae643cadb=600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -7617ac597cc32b4d5804938b024729c826a571db621b6084c3387028abc7a5da=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001a57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001a57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +7617ac597cc32b4d5804938b024729c826a571db621b6084c3387028abc7a5da=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001a57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 7044d816d041064224679b185ba14bbc395c4c8c1a2fb2c219e6c9a75107e8bb=600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 45728a2ac58cfda8b05d4fa2a87108efd6f608f2febc22b54fafce5b827599cc=600960086007600660056004600360026001a57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 546756297ca7be8134054870e2fdecb2baabbbadb7802f85546ad2565bafb142=600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -623cb76cc7f263283e14a83debf2be6d33e6387b7ca4c291adabeebc28b6cf73=60003560008103604657600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +623cb76cc7f263283e14a83debf2be6d33e6387b7ca4c291adabeebc28b6cf73=6000356000811415604757600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d97882037d93f9e6a488a09c902811b351a9386d76e4d6917b3d4dde713d4307=600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 3727a46ef1cf11f260d99eca5376cf92bb901638f2320eb0d4c1a1ad064f872a=600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c3dab4fbd966b4bf6be70ef971bc0cf0ea416edf2d43eb32f17205c1f06f7cba=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001a67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001a67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c3dab4fbd966b4bf6be70ef971bc0cf0ea416edf2d43eb32f17205c1f06f7cba=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001a67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 905e8d8f6cb731f9c4eac2508b3fbdd103b4d1f9a220ce70b9cacd3b06de8ed9=600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 9170a721847222a91f022445156dc1f7e22b2c508241d29b6034ce8ccadf051b=600960086007600660056004600360026001a67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 089e0113da900c9baf841ee09f9976c1d5fa817a4f66301005fcae69fd2851b5=600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -2172a5bbf7248de069dafb926cffc6b486cd3f5e7363cd67e6d9bb7e09d6b987=60003560008103604657600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +2172a5bbf7248de069dafb926cffc6b486cd3f5e7363cd67e6d9bb7e09d6b987=6000356000811415604757600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 aa7d40c64d7b03188e2196062bfc3145a39d6007c5ff6241669fab753e1d1e22=600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 68630c36bc83e50c031d5a843b9f69c87a31262fe579c318afb46b09f6fd2b80=600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -aa4683a35fd38194581d7a313b9d03d3c09f0651550f7ecd6bee2890ceaf2842=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001a77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001a77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +aa4683a35fd38194581d7a313b9d03d3c09f0651550f7ecd6bee2890ceaf2842=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001a77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 4c7c09173ec8b4b0bc4f84eea4836c54b13cb5fc9a2001256801fac4b73dcd98=600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c57ce6f6d2a0dc44c1b5ea88555ddfeba94c7b5a90e88d099d62f24b93644a49=600960086007600660056004600360026001a77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 8d70f65be4dfe1874039f917afc337fc0f78c9d73ec0cf6f87952407479e26ba=600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -a2deab31c731cb19a32ee81b5dd1fb8dd0470eefe87bece2fd3fa79fed1f1efa=60003560008103604657600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +a2deab31c731cb19a32ee81b5dd1fb8dd0470eefe87bece2fd3fa79fed1f1efa=6000356000811415604757600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 c36ee9b66f33ccab08ca07a6652201f082d2bd94eb36b04daadd893dccf6b965=600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f430a70af6677071abf68b854672da24115e8d63aaa840ad0e97dc1308a97b3c=600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -622d029430a2cc1137ab7ba37a468fb2bb3605528bb5ce612fc1b1e51cd92473=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001a87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001a87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +622d029430a2cc1137ab7ba37a468fb2bb3605528bb5ce612fc1b1e51cd92473=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001a87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8a6a4726a21f9b7c1a94a620ced3d9fec8a69190f8029c2ea0bb0ad0938ed425=600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 ab14c2fcc9ded0061d67077862e0acc84a9e5482e85859418fcacad7212d4685=600960086007600660056004600360026001a87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f1fbc47491951df62388ad0a6aa79863a6223d9e97069a12ed84896fdb947444=600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -648d9c3d8273fcab8e7b98a3d748652514c00cd53c9c542846d8fc152b554588=60003560008103604657600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +648d9c3d8273fcab8e7b98a3d748652514c00cd53c9c542846d8fc152b554588=6000356000811415604757600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f19dfbe8a65ab6d3733b1b2e67034aa0eebbd4b47b53db891098e6d1ce93db5d=600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a72f444d49095ff1ca7447104f75e88ac9870f742c100f62df082257c26946fd=600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -33704028c14ae91be0d7da306465314c2bbdf085bb687c43609ef8ce7df5eab8=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001a97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001a97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +33704028c14ae91be0d7da306465314c2bbdf085bb687c43609ef8ce7df5eab8=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001a97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 ee898162a2c27aa90bc90d003ce02bc1d506fa8788cbe3c69f0fb36f3be2a2e8=600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f7a6f24172fc6615b21e4fce5d6f8d37d9250dffab35bf76320ea31a7f989b76=600960086007600660056004600360026001a97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 0259856d6aef71d5d73c6369a5b22de974d2b441cf01c6e8add0f29039a7e21d=600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -dad74d4465d591ea226d9264970f547f9d4b7f6f9c80fd069873d7669d3f13a5=60003560008103604657600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +dad74d4465d591ea226d9264970f547f9d4b7f6f9c80fd069873d7669d3f13a5=6000356000811415604757600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 295601473c4153b15be75da0ea7f2cfc9f5b402319469b549b78ae66b1392e01=600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 6eee4cca6270f0aa318bdae5d978343e4d6cd121c1e07fbede1951e345114c3a=600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -1bfe22a37bcb20eb9485eee47d820daf3972aae460efc38c72b2dfccea7021e5=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001aa7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001aa7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +1bfe22a37bcb20eb9485eee47d820daf3972aae460efc38c72b2dfccea7021e5=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001aa7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 04da003845cd78215fbcc2de15facdfe22cffe9724e0f31825e70706beed643c=600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 091fd439ce89bd0d7c76bc50722fcd05bb1a406d2ff29addd449576cba3e396e=600960086007600660056004600360026001aa7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 7eae079129300611085a8201bb2748f6e5d0086df9301207fc7539f774657776=600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -03cd8ab90e3393d2da8f899965a864a80b0287674c891e7a84761286f5922f99=60003560008103604657600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +03cd8ab90e3393d2da8f899965a864a80b0287674c891e7a84761286f5922f99=6000356000811415604757600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 cfaa42b334629e86f0d984c20cc5d2d72fd634f816658c493e080fad5577c92c=600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 0cde0e487762e59d9178c148d5669503e3e80b9e0b0a7cd4ef2aeb0b043d49df=600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -656b84b3aa8ec81eeca08cf8c56e595a45e32076429dc249c91e7a5638d7facc=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ab7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ab7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +656b84b3aa8ec81eeca08cf8c56e595a45e32076429dc249c91e7a5638d7facc=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ab7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 38ed1b839b2e14af0ecfb0beba968e9ade19702be2c7defd53f01e68c263e6d2=600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 e39774a762fb20a88645672dfc2c74ce0822560179cf7507d5ddc05ca1481ef3=600960086007600660056004600360026001ab7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe a3e5a64802f89fce1f32efc513b486ac0820b0b34685b8fb0737f9a6b4180a8c=600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -24efcd39ac3cdf3dde99e1b504caf4614b03d4f43ead5f9beacfe8be4ae816b3=60003560008103604657600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +24efcd39ac3cdf3dde99e1b504caf4614b03d4f43ead5f9beacfe8be4ae816b3=6000356000811415604757600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 465d137cae2495e4fea7763aa4da24bfec43f79e4039aeed2631000950c0e3dd=600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 bd0de9ef240e2ae2c3dee263eb8d295d979357922169643f7fbad4fadf3203aa=600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -4a91f97ac5ec001bcdaba076904646eda8d0911267ce0bd3f7816d1b0b2a381d=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ac7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ac7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +4a91f97ac5ec001bcdaba076904646eda8d0911267ce0bd3f7816d1b0b2a381d=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ac7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a5512c98710041a04f287685c1eb58b7e9ef51dac1b73198c3e891cedb404317=600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 69fc317a70e7d65296a306efc4741f68405423cc089d4bb14aab766838b3e152=600960086007600660056004600360026001ac7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe e79010d4bf814f5120e3396e358b55653ca0a4360bda3397ac2ed928a6c2a015=600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -92375e3fd5eecf61074e7259bc7e2e32f83c71f22da2cea0ccddaf6022323169=60003560008103604657600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +92375e3fd5eecf61074e7259bc7e2e32f83c71f22da2cea0ccddaf6022323169=6000356000811415604757600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 c212f1f96138ae71c8933e72aa994bd3e192bcc21a09c6d767b078f150f4553a=600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 c1739198be2c296443151fabb12fb05b7f4ffe17443adbeab1c7fed63a56a882=600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -5bf1a319391892e8984f26d09759eff4e0d2e5ebfd94c92e82cc668ae379d931=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ad7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ad7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +5bf1a319391892e8984f26d09759eff4e0d2e5ebfd94c92e82cc668ae379d931=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ad7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 545be1cdc1c5a237b85abee063d9120ea2a05fa6925ff6b0b33934f610461832=600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 fedf639ff904520415f367ac44356cb354f4bf3edc09eedc5dae8fc35d770b37=600960086007600660056004600360026001ad7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe d461f93244983a64bd0b0382e66618c6a20f95e121a0d824906ab123e5ed790b=600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -714e679483bf1a87a19bfb1cafc948c27a6776fac302505f89675503d4d31faf=60003560008103604657600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +714e679483bf1a87a19bfb1cafc948c27a6776fac302505f89675503d4d31faf=6000356000811415604757600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 92a2f94f47279694ebe05abea98e523dcc77834cf0aa46b71dc20fffabeee61e=600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e25445ec2ded00e9e890b3a5adf8a6be5ad404bc6b59af04ee9043b555030ebf=600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -cf3e714196c6f7cc168f3149daf08cae9eb74da0bd1096eb6dc3826318b38ad8=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ae7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ae7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +cf3e714196c6f7cc168f3149daf08cae9eb74da0bd1096eb6dc3826318b38ad8=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ae7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 39280436baea12152a641f69ec1915b38370be4ec75797802783c6225a57c7ad=600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c9e403e13ce264fa6669e004e8e519a4b3355125bf857f5eba1e7a04df1426f9=600960086007600660056004600360026001ae7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3598fd8bac38c5ab3fd4330ab554809e1911d8bbe08762f83a1686b68c6c6b6b=600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -eb8f7a432c7cda4f93de0e9b1fb9894f1a05a5a8b3a64b8d81e0807c9614d063=60003560008103604657600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +eb8f7a432c7cda4f93de0e9b1fb9894f1a05a5a8b3a64b8d81e0807c9614d063=6000356000811415604757600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 18028922015b199d55fa28bc39c483b5dac60dbd99f2647189299646209d3f4e=600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ff43a4b6bd4f497c81600f4b31f55457e17a0f2b8e51bddcf1cb73855a68a642=600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b813fe4e9ca8b8d5eb9de231f8577ca1dd344b0d804ec942b5852740b680272a=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001af7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001af7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b813fe4e9ca8b8d5eb9de231f8577ca1dd344b0d804ec942b5852740b680272a=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001af7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 34f0a9b3798dfc90a5de90017cc9e9225c2db1ef43fdc4acdb6ac0632ba7fe8e=600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4bdabc9cc4cd2dca72f8be241b8ce0159385a80f03ee15e267901c1ad0137886=600960086007600660056004600360026001af7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 6580f3abd546f8acf7550390002de2cb77194e9f4a1552586fe1669e2d6152eb=600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -3b58ce1ccb1bff45ac0377b154d262698ef5951667d644d24afc8b5228b1e368=60003560008103604657600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +3b58ce1ccb1bff45ac0377b154d262698ef5951667d644d24afc8b5228b1e368=6000356000811415604757600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 23ac936ed2f76cb2295e9492fb292f61eb377fd35de083dfaa32caeb883492af=600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 595b56b882e1c748c6ce52746e5aaeacf5829509d13e566d20766708951b6de8=600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -1c79ff878b728067cceaa9dc5013ffc81bbe10a6b35b9ec68da3b7cb597544d5=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +1c79ff878b728067cceaa9dc5013ffc81bbe10a6b35b9ec68da3b7cb597544d5=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 fe60968b98e5713e5717de453aa6e7f59607afbc23edad154615882624e22a89=600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 79e65b2e2104a8925e1bfe24aa5f1836fb779bdc4779335b77d1471474c79aec=600960086007600660056004600360026001b07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 93c5046ce9a0ceda9b15fc5973038054e3fe198bb5499252667e528910761b60=600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8f54b1af2c7db7e47322314d4a06b9b46753be55dc629dec8adb17185bf14147=60003560008103604657600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8f54b1af2c7db7e47322314d4a06b9b46753be55dc629dec8adb17185bf14147=6000356000811415604757600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 375b5d3f62a035eb2b1865ecf1e9c2ced18053d504dc4118c8f709fa04076ec8=600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e16ebef2c62fa5608817d23362ea324c2ecfda6f683daf18f9bd3ab4639b81b2=600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0a0b3e15d26674691a7e70d24e04e701aac766224f296a283a45af17275854f6=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0a0b3e15d26674691a7e70d24e04e701aac766224f296a283a45af17275854f6=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 124fe5955b02e4ee014861e023171c6fc4910083f3a53cbc7f5ca0abe1b0c314=600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 5f75a8c43a8a45708325265dee57d9304421d3ba7466dd54bcbd93551b09c6bb=600960086007600660056004600360026001b17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 75535d4885e5f908585c7adb2fe96c6acb264a6a4e08c380050a2479d7c19d85=600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -3af4eb3da62fc565046e8f3aa54fa54ec36914e466bef0c9e4c2edaa5c216241=60003560008103604657600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +3af4eb3da62fc565046e8f3aa54fa54ec36914e466bef0c9e4c2edaa5c216241=6000356000811415604757600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 6d47c3cb6eff5e142423c64e46fbb8ba1933f14485da3b8e9ba8ee410ae70c8f=600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 671b4f416fb000cd2c078ead172cf30911da23657143463dec98e974490aa0f5=600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -36a77cb26e41113db21c7774e6dfff07da405edf2614a1a57750ac80e724af43=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +36a77cb26e41113db21c7774e6dfff07da405edf2614a1a57750ac80e724af43=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f0c3c5eed4b608a5347b90251412db3927cc57fe5f52446d74b80160026247d7=600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 dae7a64245fd8264485ae19feecd4081291ecb49861c638a4fddeb9a662a5219=600960086007600660056004600360026001b27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 928e010688153b6d9552e29afec10b51d52a3175b8aa3b0562251ab9e0b2fa6d=600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -22170866d87ea1fcf07fcd8c36072b1b399719e0146cfe6ba92c1fc131b7c95e=60003560008103604657600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +22170866d87ea1fcf07fcd8c36072b1b399719e0146cfe6ba92c1fc131b7c95e=6000356000811415604757600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f1c7bb44fcad11ceb3b9fc7a47fe2e26e00b74bdcd085173433f7b5de6e38980=600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 469439b15a646f36c5427bd314a7f3dca16e45a4f678286f344c91c25b77a5b6=600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -36bcf0fa2bf92207c4936243b58b43c7c5b4a00f238be2427061f4d5b44130bb=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +36bcf0fa2bf92207c4936243b58b43c7c5b4a00f238be2427061f4d5b44130bb=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 78a6788de72feb7e1e104f501e300fbd6894242ea6f54c7d72fb9a1ec0ff8477=600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 781f806cb192042e5088fa9e50fcc5229e6175cb5fb5e28a66ccf48cd2e32f77=600960086007600660056004600360026001b37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 2c0430a512830f77bc21d09623504c1fde5e358d30b51dc419bf0af446aab731=600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c9a36209c89dfb69f00264a028ec5d4a69637f3cba0e90091a2560887bfd0574=60003560008103604657600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c9a36209c89dfb69f00264a028ec5d4a69637f3cba0e90091a2560887bfd0574=6000356000811415604757600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 4d17d1349fb9f995833650a444ff16c18827e3dd1b38ea6d11d42168dd3e6251=600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 32c1087d13a89661f0d090b01d2908b03da0f044368020440f78a0c5887475bc=600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -982fe1590c1f12ddbb79d0995340fa62d6136498b2a8b26203cc9ac804b2c79b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +982fe1590c1f12ddbb79d0995340fa62d6136498b2a8b26203cc9ac804b2c79b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8c73894e63fb9113d3fde4e1226c32143091f0f6d2938267960d24eeb532095c=600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 810d283fa069e990fc35355a8e236c9455eb032ca179ca096e5e334d10b15984=600960086007600660056004600360026001b47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 6801bf09c7edba24775aae91fd05a0b5a76e29e32ba89f87ec41f9177c00730f=600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -afe2534a3f30e8ab5742f1822626c38b933f2d7eb3eb3ff5d0ffb9c412f47f42=60003560008103604657600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +afe2534a3f30e8ab5742f1822626c38b933f2d7eb3eb3ff5d0ffb9c412f47f42=6000356000811415604757600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 32e499d14f918180bc38b8a9d48d47d77c2b9b9b774a5e58488fedd697597707=600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 51ef377562e53c18f2c0c8ebca6d060f913794967a619507bbc0a4a91d31fbb4=600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -bf14c2273eb002a265ab4fc35d3f4987e02f56a4e3434e40e719a659c1da7d81=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +bf14c2273eb002a265ab4fc35d3f4987e02f56a4e3434e40e719a659c1da7d81=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 7a912ed2def5530349bcac97a961836f04f79978466c1951b5c4a17626bb8540=600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 020af5e103d2f18a385ff9969ad5a4cc1f7879edd42a44deaff1382ccd6ae262=600960086007600660056004600360026001b57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 1640682cc01269764a2ef366cf43fea58f95405bda149a2148eb0bf9dbab9aab=600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -928a8b2a29b3ccd0643acbb28da10364a97b1493f0f036e34ad3b05447bf956e=60003560008103604657600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +928a8b2a29b3ccd0643acbb28da10364a97b1493f0f036e34ad3b05447bf956e=6000356000811415604757600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f4477b5d8a992e45bb09f463322830800845b324a87edcb990b242ebcad55112=600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 fcd8e234f92da37c67a6c7290fdc039a69fbb2cf1c8eb14be7749d7ca5225156=600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b08254d18d2253b2d0b26707744350cdd9f6c86cac8a61072807f8e59ba2f191=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b08254d18d2253b2d0b26707744350cdd9f6c86cac8a61072807f8e59ba2f191=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 4f7396a5055abb9752060645295bfabccbe44ac99987d863c4d844dffe9776cb=600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 47817da94d6bfc0115b8f8a4b0998700721e504f5e67f072c3b06e6e908bd57b=600960086007600660056004600360026001b67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f88ebae2e2b0720dcee15414637fb3d3e32446e0867d6ec63de508cf0a87c5cc=600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -a46d8c215ef747e4cf6f9a5daed023e2f50d863301065ec125eec387bc2e95d2=60003560008103604657600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +a46d8c215ef747e4cf6f9a5daed023e2f50d863301065ec125eec387bc2e95d2=6000356000811415604757600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 dc47640e378fcf9d691d6b599259f7f5527ac41277fd7d5bbeedb957b4d80d49=600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 74f617c08a9bcbb808bb8f7104f7b3d29c5c55bff6992bd4af3e52fbef7df05b=600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -32e5491651bf426b83a9498d4dcba4e2d908a491d48c98e5b863d8dc08f2b54b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +32e5491651bf426b83a9498d4dcba4e2d908a491d48c98e5b863d8dc08f2b54b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 cd2dc524aafa37042e23a0e44f11be551e807bec5d92118babee55c00220ca3c=600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4bb64ecefd2002ebce9297c45a1ce2c990b131db282d56afa78a70aaac859511=600960086007600660056004600360026001b77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 18b26b6ff4b692a2f45c3e1795cd7d33a384e3d5d75dba5fb5c2cb3188c1dd17=600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c5f510ab27978d1ed30488c56fc1431396198a2e7b02c14bdf5a2223b1a314a7=60003560008103604657600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c5f510ab27978d1ed30488c56fc1431396198a2e7b02c14bdf5a2223b1a314a7=6000356000811415604757600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 060eb32a46ac0a0a127d8ff499441843b9a7fa40b1a616206dc3192ef8c76053=600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 41f21ea7974797fac4d5489776481d7a2b62ee2bf514079761224a7b8e131d33=600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -f58cd0f4b2167441afd6ce239d2bcb8ab537f23d13a8ef0b3438cb80310a625b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +f58cd0f4b2167441afd6ce239d2bcb8ab537f23d13a8ef0b3438cb80310a625b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 4ef5b0b7d82b26ac3d4272e69e908eb983ff9247f872a6b4f8e5701163da4ac2=600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 56e3a592dd11a809a75deff30b01a591bd237f91271ae0d290f1e452f45e8664=600960086007600660056004600360026001b87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 19d81279025ac2acfc0cc45a874ac42706d42f2d8b311d3758027066f22679a9=600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -ab05337b437e65da194ed9c8a563c5ea899b96e4dca691e9169b5c8978ba4f8e=60003560008103604657600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +ab05337b437e65da194ed9c8a563c5ea899b96e4dca691e9169b5c8978ba4f8e=6000356000811415604757600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 68353f05fc7e97c586eb3b8bea79b0360b0ecd5af70040e76a85eb8ede03fe07=600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 4f6d5424ef81c065114c560a6b9c7b642ed1ba0f7e32729c4f9f83908934619f=600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c1e1ad645a498e3daec6fa098b38f2b1aba2ce869d5b2076fb236d094142fdeb=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c1e1ad645a498e3daec6fa098b38f2b1aba2ce869d5b2076fb236d094142fdeb=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 714ed27fbcb26b98adc34d507e6e03645f80cc231e43386565c2afaf1f83a3e9=600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 eb3c3c4986684fdc2068398c4684f100ce78a6e3142dbcdd4d67f463d5460dde=600960086007600660056004600360026001b97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe e450e874f29d34b4480a880a9e31db38b01e7bb5bd4693c7e3bd258d0fb701a4=600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -63c1b930bc412b67d7d24253b1d20dd1985b214b72f368a3e6842009d2ec9d62=60003560008103604657600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +63c1b930bc412b67d7d24253b1d20dd1985b214b72f368a3e6842009d2ec9d62=6000356000811415604757600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 90b4aec00af9accae5e7f5207d4839b95d28df1c249e6f95b0d961513cd1e572=600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ad7d9ee1beca4b66b8bc39911b853419ba26c05f2f312c869f9bc4cb21a99229=600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -6c050fe5c83db884e90b5aa7e7386a3ec77d1e1247351c3e2fc9997a079b22f7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ba7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ba7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +6c050fe5c83db884e90b5aa7e7386a3ec77d1e1247351c3e2fc9997a079b22f7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ba7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 885031d46e1d825960abd359a762b9bb464573c652043bd5d75eb346d26815ea=600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f557552f010fc2c4caadc4a38b60361d65a83bd932bac36149ee79992531cb80=600960086007600660056004600360026001ba7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 56ffd5c13a4aad794d26796e681d74b8a3384e283301828adb4568dd38b05309=600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -11ef9a4a25acb1844a4b010af5eee70f1351d3edddb4348cb1413d48c2fdee50=60003560008103604657600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +11ef9a4a25acb1844a4b010af5eee70f1351d3edddb4348cb1413d48c2fdee50=6000356000811415604757600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d9c20ffb6352c592ed47ce05fc10defad6f2b695bdb61235f4ab457e6fed13f7=600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f587a62ed97890df766b66bea9ec2ef86fc697ee3eff9a248a311f95bdd603d8=600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -2ae87cdc2993ba049ebcfba248401241c35aee3134c3867974cac31c19f50102=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001bb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001bb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +2ae87cdc2993ba049ebcfba248401241c35aee3134c3867974cac31c19f50102=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001bb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a7ec3e451e4df447640e4faeb5115d4717d6d39c95a4e93780d6f286ac740130=600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 a3da684d2da4a84617d15196aece456f0c6c3410718e4f241356885418334d74=600960086007600660056004600360026001bb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 22c231e7da3c71b41c76b4c8c93e6429b308dfdb59357f4675e2da62b08d2df5=600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -61c9a242cba0f3a0691359ce010ba50cd8401350253c695b7c0009f5ad6e746e=60003560008103604657600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +61c9a242cba0f3a0691359ce010ba50cd8401350253c695b7c0009f5ad6e746e=6000356000811415604757600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 bbe32aa859c49ab5fb458dfe83d006331f8cb98d1a970cc5978201eabfade8ad=600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a9d4c65cf0b8b6e2c9a0fc33714c44737efd898474b67c009e3266b20ec6b83e=600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -afb0383f74c8fb962e5a94e2714ff5b425e6657c505b382442bafac93e9753f7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001bc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001bc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +afb0383f74c8fb962e5a94e2714ff5b425e6657c505b382442bafac93e9753f7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001bc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f21d9bc01a0741c0e702b32d09bf28d6749ec517705d1eb7238fd403c2921427=600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3c7ddf8dd24b16f19a47ce5eb3ac90d2128a35049e4ce0ff4b99fade851ca8b0=600960086007600660056004600360026001bc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe bdef3b665cd59dfea57fc602d5017e1e8eb092c15b355dd0456d94789be71e31=600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -4237df860359f33d365a69395d5f321d4d8b7ee1e9166acf6214c0fd4cb5ad0e=60003560008103604657600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +4237df860359f33d365a69395d5f321d4d8b7ee1e9166acf6214c0fd4cb5ad0e=6000356000811415604757600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 2ea5eeb8ef97f0ff1f8aa51fa11c7213de8e1d1be8f878f77fc98f808608938e=600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 325ad31a49d67fc404441fc41fe1bdcccc34b0f17a6ab6f8238c14f0d0dc97c5=600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e84edbf58da2d1e6f701242356a9ff5c710214cf065f587a6c98d432670447c2=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001bd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001bd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e84edbf58da2d1e6f701242356a9ff5c710214cf065f587a6c98d432670447c2=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001bd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a516af5aea961e1fac619bc19a11abc7625e9ab59754da20190a65f6acb189aa=600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c1fd32b16a5b0f534498e1d40c344c968069951277a01e791c686185bceb542d=600960086007600660056004600360026001bd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 92cdd0607a0c0d8e28a101fe5df98d04376d85e02863f5bbf3cae30c2d473e45=600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -4439a26104f7dbd9b240afb41bc818231979bc587a218d552de0c8373f61890e=60003560008103604657600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +4439a26104f7dbd9b240afb41bc818231979bc587a218d552de0c8373f61890e=6000356000811415604757600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 69e10cddc75cda5d4d1ff9cb935650afc2118cdf1db4a3fce6caff616ede500b=600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 b96f19b1d24912ebb702f1c393305b4cf2fc2a1cc9d6ac69d6b33b97bdf38ed8=600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -9781012481f678a36f86a25b86fb52d017479dc87be9a704c6a2d5cddc3e7477=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001be7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001be7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +9781012481f678a36f86a25b86fb52d017479dc87be9a704c6a2d5cddc3e7477=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001be7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f29704b621a80db5c5ee36cdc261e2a7730f418c374b2e1634cad6dca0971aa9=600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 969208a452514723bf359c36fbe83a921e78b9e24f906637c95c63595e1e599e=600960086007600660056004600360026001be7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f9fd9ca72e3f03cccf514d064261ea2415ba872125a85517f195603bd132e778=600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -7633c312f2d5e65fa6721fba58659feca6ca4bdd05d0bfdc28b1ec3b34513a64=60003560008103604657600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +7633c312f2d5e65fa6721fba58659feca6ca4bdd05d0bfdc28b1ec3b34513a64=6000356000811415604757600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 57b73f83400b5ef877cdd52844ad09c82b8fe390d58fe63ebb018ae6ea00c481=600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5ad24ba6a729b87d21f517a92ac64f275229d61d93421b2d66982d9a059ba29e=600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -90c69b12e37f9f8ee8ee52cd8e9b7062cf48845e25401c64d52bea5026e906f6=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001bf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001bf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +90c69b12e37f9f8ee8ee52cd8e9b7062cf48845e25401c64d52bea5026e906f6=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001bf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 baf5c820aa3e58c78f163531e8e2472a5cb184c6e2e6fc32f1547bd84307e656=600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 486ee7d509561e73aaca3f243feb8c1ac4e30807fb2d4577fb582f25e8ac81c8=600960086007600660056004600360026001bf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 4d2c16a28c19d6fb0386ccb9005fde6d62c8ca4a5a30a4c18424f096610c6b8a=600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -5f46a8529b5e1d3b165b4ee0b775d9d441dd780ff7af26154697cdb10199b760=60003560008103604657600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +5f46a8529b5e1d3b165b4ee0b775d9d441dd780ff7af26154697cdb10199b760=6000356000811415604757600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 aab5ea36b89f5907f0f139b28e0f3ee64b3b4e074b2baf8d16b70356eda8c72d=600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 43a33476d20d5465f15b69b5ac3dcba65e253264b229885b18709f4efe6d513d=600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -440ec0e78611df0b764686eb6810cc37c97827aa13e57ff12201bf021ef0eda0=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +440ec0e78611df0b764686eb6810cc37c97827aa13e57ff12201bf021ef0eda0=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 6e352e2ebd9d9bac28494cab053a3e4d67401baa7484d3cadf318cf18ea7c4e3=600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 1ad9173ac7b3cb4a897a6a58070706acc250504ec6daae074a01ac15c4150fb2=600960086007600660056004600360026001c07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 6fb28d0f57446bdba873fb68f0972bcffda1250fe19012c87dccd30f4e472e44=600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -49cd5faa9fb3e42f1fe31081b56a22ba654ed76197bfb0a2016bd6d6fc1f27a7=60003560008103604657600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +49cd5faa9fb3e42f1fe31081b56a22ba654ed76197bfb0a2016bd6d6fc1f27a7=6000356000811415604757600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 8e657bb75f00a0297400a3a50e4a6b40c23f255530ebb0530afd60b3c19d53b8=600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 368e68be00e685410b86a60080737fe47b7fc9857b479a25372224c6763df8de=600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -8723ed6741f8d8fb5be14f39f9cbd1b908133c3db40ff77d229f8a6e22f669b8=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +8723ed6741f8d8fb5be14f39f9cbd1b908133c3db40ff77d229f8a6e22f669b8=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 dd628deed7e03429ba283bc2d2898d18cdc98c23fbd11b33a0f3156e733bb776=600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 6a87672c9ee5e435040ce2b29286e062cf1aae0f571a42a3a98d60283779e3c6=600960086007600660056004600360026001c17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 069be315142d5ae52faed421c0aff3f3a6d217a81efb09d7d75a353491e8184b=600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -234b6b37e76484cbcee4b1dd2cce1b2f8d773d64f98df062c466099e7e6926c0=60003560008103604657600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +234b6b37e76484cbcee4b1dd2cce1b2f8d773d64f98df062c466099e7e6926c0=6000356000811415604757600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1ce96ce059b153a9e8802e6632ea68c611876ad0b238204659161407388fc332=600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2162c46f2802de086aa7f2056f60574bb25bd74b4f005f80529202067321ca8f=600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d5e04f14bd81b88c48371518f9f6ce4cc862b25d7ad266ced28beb79e814a386=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d5e04f14bd81b88c48371518f9f6ce4cc862b25d7ad266ced28beb79e814a386=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 7aaf6a69cba0b1b8f4da62eb864a4b2a9b340d60dc5a6a40ea0807873f58d16e=600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4a004cb232cd1e3a18e12aeca88a7efac99815dcf28292244b346c27e445ff3e=600960086007600660056004600360026001c27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe a2cd69df723f90bafd39ea419d93c4ef4f4572831db7b45cccb7461d902c8cf9=600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -974f7984dd282554276542e774e708d9fff20311c449fd16921c3088553c3a72=60003560008103604657600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +974f7984dd282554276542e774e708d9fff20311c449fd16921c3088553c3a72=6000356000811415604757600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9bb857c9bebb6c8d81a51785922eb45ba1f92a6ed98738f7fe0405ac49ca7d53=600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2b982e1a87489c81cf9a368fefd6a74a9d9f72ec9c0d0551acadf19ca7bd2273=600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b697e84cbc6834254d4b76d3aae988420d5ad35d4f09ddd95cd4b5c0a00fdf9e=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b697e84cbc6834254d4b76d3aae988420d5ad35d4f09ddd95cd4b5c0a00fdf9e=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 4d96fb0435b0d495988e9e29144bb21494dd1fb222ef9b09fd45bd624135000a=600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4b22465493b76a6aebfbf2a73ebe5a22f4ef92685c2b83cb99472c4bc7c0f896=600960086007600660056004600360026001c37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3211d35021f25e0987cba652ec37b9e39657ce55a42877fc8df701649ce0cada=600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -f1516a4385c86866869634bf6949cb7fb3d1ce8141ccf858f3ab96ed87447251=60003560008103604657600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +f1516a4385c86866869634bf6949cb7fb3d1ce8141ccf858f3ab96ed87447251=6000356000811415604757600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 439530133f2228fa8e0dad386601dc9695a2d09a01a803deaaf39ea5162241e2=600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ac6dcf8ae0079e8d984fb01831ad21afbd824fada61ee5fc1b0603c96616ac09=600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ad79ebdd32f48ba8ddc1ce9a9476ec848bd139f9a2ddde614138955d4689b242=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ad79ebdd32f48ba8ddc1ce9a9476ec848bd139f9a2ddde614138955d4689b242=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a4b1246e81e1369d23fb22273dac81fc1b8598cc6cb14f71cb9aeeb00a9d04fa=600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c892dede084f9118b019849b9be25a068558251f5430a4c1921921845ca8f512=600960086007600660056004600360026001c47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 615252e815af8eb1de05741ea6ab2c7d03d00af4eb87e088d341fffb871fe754=600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -5e8e0a54f184c32d46fd08bdade18d6a8d3fccd64c87cba8a7703b38f62c7336=60003560008103604657600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +5e8e0a54f184c32d46fd08bdade18d6a8d3fccd64c87cba8a7703b38f62c7336=6000356000811415604757600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 0375fa912edf2f7c60cf125aa617f5dd3514a1356545df920965d08c41597984=600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ef168ca331ba8645a99cc6cb80283d220a5ed8cd973b491d4c88bbd9265b0dd6=600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -3f32f88b66bf79172337e14f8f52104b5d200d429dcdcfa6f93192a5d6629782=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +3f32f88b66bf79172337e14f8f52104b5d200d429dcdcfa6f93192a5d6629782=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 b8fbeb85cccd9c76387a9cee0ea09c4e8a943ce8c2ee47ae5b7766dc6fc690bf=600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 2dfb655ecff1501872f5979d451dc466a49c234ddcd8ac8692a36a9d91df4f77=600960086007600660056004600360026001c57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 88b21439bf1281ae594679796592b8952dc990b55d954c2a9915abc9f2703ce9=600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -08496e3e273367dbc053d796145e71454729616fac8c190973153de07904b6a6=60003560008103604657600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +08496e3e273367dbc053d796145e71454729616fac8c190973153de07904b6a6=6000356000811415604757600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 4d9486b483e2f77620501d46a7caac785c5d2bc18be0bf4d30dd2478d5c7c75a=600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 73762e0d992f8d0ea797598c83cf6a377707170d51e16aedd139629f629c4f1c=600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e9a4c9f4ca05b4b4e9cf162d01dbbf480b6399185a17e8caf0ef41119e39f4b7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e9a4c9f4ca05b4b4e9cf162d01dbbf480b6399185a17e8caf0ef41119e39f4b7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 ea271447fed62860c072b33063cd8090b64081faf695c1bde2d018e826c04d31=600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 813bfd0b2011043a0f2cc1357b62e042d3fc33aeb1e132e58af04f847f1c6746=600960086007600660056004600360026001c67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f591e793f6861eb3c3de8fd1bfa638d3cc470ef12dea27e0164ebd28d25665c4=600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -5f115fc96d83aea046796b3a2506102bae1afbc207f908fc4c9a8e148afb3b6b=60003560008103604657600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +5f115fc96d83aea046796b3a2506102bae1afbc207f908fc4c9a8e148afb3b6b=6000356000811415604757600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d5335691ff41d95710b99a76303028bf42de25eaf85a8dbe61433792cd6262c4=600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5ed0e3fbb30789c1b44fa44c061ee79566cf2963e02fa490a5ca3b08b23cb521=600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -13e9e5ac7f93cca3980104b053f3ad103533c797703864ed22277f9ce7107569=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +13e9e5ac7f93cca3980104b053f3ad103533c797703864ed22277f9ce7107569=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 380d14538a25f7c64f6b81b5a5e38fe5fab66c7180d90845a8876c938478aede=600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 1d14163cc318001db2bb78675bad098c084799c5dedad0dc12a6428dbb17c6e9=600960086007600660056004600360026001c77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 120cb7b7259f1ed21453a6d1b779c82de8cb2e65eacea355a1e27d0d4035ee9e=600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -35ef132ecdc159990e9b6ad2ceae338a486093fc05b57a770f38b667e95e0493=60003560008103604657600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +35ef132ecdc159990e9b6ad2ceae338a486093fc05b57a770f38b667e95e0493=6000356000811415604757600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 ac4896171d33303ef20703033f342b17cc1650dbfd30771818344ff0dc9058d1=600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5f42440bcc01b7d5f9ad06ff26a9a8bdecd35acb5ca8699196d4e55edab93471=600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -4e868c4d256b21ed972bc250ee1ac518f9c014dde98341ac2b6d9e565c90f638=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +4e868c4d256b21ed972bc250ee1ac518f9c014dde98341ac2b6d9e565c90f638=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 6f53a391ea3183a124183d8c150ec3266fd181cf10c312cd346b1f4614216aef=600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b993591e9fdcac10016723e14f857946844c0a64303a908a24100f54f9df17d8=600960086007600660056004600360026001c87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 8f3537806dadb3d4a4b60815f850f4ff5ad01e8f0feee907d69ca4cf0ea013ba=600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -0f1b2da59c4b602977dafe4d1b79597d3c8afe89ef9f71b018eb59d076c8a4cb=60003560008103604657600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +0f1b2da59c4b602977dafe4d1b79597d3c8afe89ef9f71b018eb59d076c8a4cb=6000356000811415604757600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 28f4dd34447648ec9e675bb317c32c8539298c27cfb9ff498cc10e95c634accc=600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 3b1bbf312fdde0d278d6f3f34e606cbd27d98cfc897d447f5f8037028757197b=600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d0cc642242daac82c715d9c71ea0112f8df6106a0745056ebc81dc01104d73e9=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d0cc642242daac82c715d9c71ea0112f8df6106a0745056ebc81dc01104d73e9=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 b361154f19d72fe35b479160786b939835c066ea168d45a57042771b49d43123=600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3adbb8134114e2c5d77a5c47590159462b2b74eeed2b38c3379bbc3bbe9a565f=600960086007600660056004600360026001c97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3e0bfc127758c9f9ebb12099a868a468389f4f73c69b2db4afd56bec3dd8b3dd=600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -3f2ca8c7e6934176b71288146a8af8e3dca9c054220be767de61cc27ba176ca3=60003560008103604657600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +3f2ca8c7e6934176b71288146a8af8e3dca9c054220be767de61cc27ba176ca3=6000356000811415604757600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 46dfd8ebec3c8c8ff8adf43651d4cf432fb2343355b3bb1cd230f6063c13b309=600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 857740fd572bdfd1829434b61f42b53ec3f31ac7ef3ad788677b6de599a27a41=600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c3f190c9403fea1726c7123e52f40930bda6a41c98abae21e68add8590f44f5f=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ca7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ca7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c3f190c9403fea1726c7123e52f40930bda6a41c98abae21e68add8590f44f5f=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ca7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 aaf645f4b626eff209e52b63facf7c9cb088404a4d11f26782d218cf3bc0c06e=600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 280c654513fc9039633ec318ff2bbf0570123a7eaefe2664a3863d9fcea5d253=600960086007600660056004600360026001ca7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 5d02e6a32bc8967dba0b0ad780a853d1d19505d7b792e08c92d94f65f40c96b3=600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -bf1db7109b5b16330b9442b03e834442165ac90fe17931e6a79ed334af1f79de=60003560008103604657600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +bf1db7109b5b16330b9442b03e834442165ac90fe17931e6a79ed334af1f79de=6000356000811415604757600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 70421cfebcef742f9487c2db6f68d667ef753858aaaf6c301af352d1b0871e27=600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a413342f8f17847a45f5421ef05f891bb039b7896940c4c503721546b3a11b9e=600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -abc9893ccc2e8bef454b27536ab005ebe0e7693ba75754709b8cec6c6c77bf01=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001cb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001cb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +abc9893ccc2e8bef454b27536ab005ebe0e7693ba75754709b8cec6c6c77bf01=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001cb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 7560dea88f0ac2ed905efb2f9ba2ee018caa5ab5b25148b9d6fe1c9767f68b74=600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 7254df8898b0191c5de0a4562b34d446bcf7712907f80b06ea9315a8e8f88de2=600960086007600660056004600360026001cb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 7e8ab85fe33c0c8473895fac19e3302573291ac2c6dba89e62e5b9e4699585b6=600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -16bfb54cbf3bbf0e6ccb475c5fd7245ae24f7bfb351e02368eedc9482de19390=60003560008103604657600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +16bfb54cbf3bbf0e6ccb475c5fd7245ae24f7bfb351e02368eedc9482de19390=6000356000811415604757600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 7f39f7ef0125cfa83ce32a6c4c20af7377a7df8755e37da7d7a1a6389ba57365=600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 1ec250321b9543f1a2b63b55786cb643ca5627b875f2dfa2f3821f4f08e621f9=600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -412ae4e449f6ee919062d19559e8ae94f7017911a509c4af228fe8b6832220f7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001cc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001cc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +412ae4e449f6ee919062d19559e8ae94f7017911a509c4af228fe8b6832220f7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001cc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 e0ccaf557395e255d198d6c34bf27e0aee8d4762711964e57fb9411b21e6eee2=600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 a1aefc889e3adc93641419f664b8ea9f95149d97eb8cae8a5dad4ac9e34b0855=600960086007600660056004600360026001cc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 686770c818dbadcfcd15a05fbc6df2c728d670e1868fa635a9e0e9c716cb26ba=600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -5f378f22ff9567958d9bbc63045ec893afb585a57548203da4bd3c76d680ac32=60003560008103604657600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +5f378f22ff9567958d9bbc63045ec893afb585a57548203da4bd3c76d680ac32=6000356000811415604757600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9e401dddb0173c98851dd8f2181b97d7a25699de42ae789d25fa9e16feb28842=600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 0405d3537840abcaf76d3b1c998546b198f5b6731723d276b47dafcfb1b9039a=600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0617e94807baea3f5758b9863492443530f4168146a2052aec9d02b47c19dad3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001cd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001cd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0617e94807baea3f5758b9863492443530f4168146a2052aec9d02b47c19dad3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001cd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 881c8bbef1191c85c0903fedd72e09004d647749c5bb19cc3e9d8711c0f3f63e=600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 27509aba5dd674de97ac3bc3f02ff621cd5204e8c379ea6134382a887bfaf012=600960086007600660056004600360026001cd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 523d1338396825bc37d7d890d5c741bc19ca16f5702710eb0c4463e7dce88a8c=600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c4888914c26f389aa69980067e9024f8180821fd7f2555ad685f6d63a839f4a4=60003560008103604657600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c4888914c26f389aa69980067e9024f8180821fd7f2555ad685f6d63a839f4a4=6000356000811415604757600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 47d43ea4b70f2e35c0174a4ae1735c42eaecb0c5165f77fb49840a9ffb892c78=600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ca3fa8eddd68904f7cdcf567db56125df0f53cfacdae06877cc59cc6ebf7b96d=600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -f7555bae98a13bc3cbc3babcbbad27008299fe802625d8891e63aa16eafa8c7b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ce7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ce7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +f7555bae98a13bc3cbc3babcbbad27008299fe802625d8891e63aa16eafa8c7b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ce7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 583e89c83bea326aed85a4a2a8134d938385a5ea79de4ad2579117bae4a51bcd=600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f295d6f7b7cf81c4c473520ee2757f551ae0ce2b97b11eea2eeae988255bf125=600960086007600660056004600360026001ce7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 36398ac27c1816ccf217d9b386b8f7a5be1aa664449309177ab911ba9aad0365=600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -0003dfc581f74bddc1450abd12552dcaf94121bc7295e1fbed29045883cbe066=60003560008103604657600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +0003dfc581f74bddc1450abd12552dcaf94121bc7295e1fbed29045883cbe066=6000356000811415604757600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 97dd6dd62fffecc0fc6e69e9a3015126f136fff8a8b372a0228e63397e7b11b8=600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a5766152b2a05afa2ca57cf3967be5e3867341faa344734fd2b694efafa49f0c=600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b806609a7674f3eb7ef902f665ff511113138d949164be00b3b847f1843d00c9=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001cf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001cf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b806609a7674f3eb7ef902f665ff511113138d949164be00b3b847f1843d00c9=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001cf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8764a3fbee18814e6d7eb42c119d88ea6ec6ddf9a5af976075158c867698f833=600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 229ddb8f6d9b8dba7d1178c0ac7f5231f827dc28442056b4ea17fab3522cd271=600960086007600660056004600360026001cf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 004cd42d73a275dddb68180477b7677ab62e5d6f6057658b78f9063e7c06278e=600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -839cf458c161c9fb3272afc4d4f935159ee82366dfe32b7aa5576b40849273b0=60003560008103604657600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +839cf458c161c9fb3272afc4d4f935159ee82366dfe32b7aa5576b40849273b0=6000356000811415604757600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 324f6a027dcca08b9b1c28a8b43984511b72b4ccd7d8d93974a0c6e2bd317115=600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 8adb8a14d90cb3bd6040ce08ca1608ec3f03c1fc6ad2fd13b81d82c66782b704=600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -1f01ea747ddb19f54f9dc9042d65774b8705b8ee7ad09a44f00046ff2a66e6c3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +1f01ea747ddb19f54f9dc9042d65774b8705b8ee7ad09a44f00046ff2a66e6c3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 2d5bafeb06df5023ed65dda8ffe7f2e1baaa45cdfe86c81f1d3bda2fb00dd363=600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 8bf25357302a2ba964bec400939e5db164a9af11273b528c0ebe6109279fc22f=600960086007600660056004600360026001d07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c0e4c6e0704bb5bf9f5368cde41925f637a4de4205a6edbf2b1cbf99c3db06dd=600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -29b933f1d48738476cb6774bbd6fe38268e4a8ca9114ba5039bbf553c092a9de=60003560008103604657600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +29b933f1d48738476cb6774bbd6fe38268e4a8ca9114ba5039bbf553c092a9de=6000356000811415604757600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 7fcaaa2ecb30302187e61f37facfce1000d5e6b55c42ab7be83c0731a24d4440=600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e214794f819f7b5e1305eaef18f24c1a985c98f158a18d621abe8fd21bc26171=600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e8bbf703e8a2b15300745f8e110a465726c0c318d989625eaca882de89de4817=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e8bbf703e8a2b15300745f8e110a465726c0c318d989625eaca882de89de4817=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 47fe4485c32d3a236868937fe4f5009cc531650588c5b2fc68c41b16469a0a96=600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f10b6f035e1a56675d8c3b158a752972d25e7a6b881ca653d2a51c07c6a64ebe=600960086007600660056004600360026001d17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 839e3adf3131ddd154706cc442affd253483b29fe17af2e5d53afb7c8e482e23=600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c89f6034d9a030297654740493ddc7a2a5f6e240b29684a43ad6f0fc735cb10c=60003560008103604657600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c89f6034d9a030297654740493ddc7a2a5f6e240b29684a43ad6f0fc735cb10c=6000356000811415604757600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 27e04042d96f3bfd4bc7ffab12c8e6da8dd89ded025e2190a72c5ddae24b40ba=600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 6789ae48d53a5fcfe44d3bd79fcfe6c5babe219dcb2c62f0c90d461544765644=600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0a87e0b425c4292daebce0ea27c5f00546272c4638017ac11b4b32b0473afa21=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0a87e0b425c4292daebce0ea27c5f00546272c4638017ac11b4b32b0473afa21=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 c1faf1fa66ce438c83fdda08f99d9493edc31fc175dc063fdaec53a617021634=600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c39b88b457679ecd4fc2ac6b6327c1e1fc72686b55a811d51832de64d5b1946d=600960086007600660056004600360026001d27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 662889ac99a3ea140e46a9b23c1c0e93c36e424a8b0bf9c470caaa64120f9398=600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -b6670619113d57dc4d111396d11f5d88e79fff101834b4e1bfd5a1c6a97046d2=60003560008103604657600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +b6670619113d57dc4d111396d11f5d88e79fff101834b4e1bfd5a1c6a97046d2=6000356000811415604757600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 7a817fd5ad0721df230e0495b386b7f86fd2b478ddb25af2dcdb69f3f970e36f=600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 9b0334b33fc11550c7d3f46efbfaebb1d863c986293f3f33700b00f11aa2181d=600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -93c2648c72a95c6d10f6ca25e6fbbb98bfe781fed47bd28b8afa0c2ec546d418=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +93c2648c72a95c6d10f6ca25e6fbbb98bfe781fed47bd28b8afa0c2ec546d418=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 b35e3f5d8e752fc1fed8671de2fb3d95d42c67b490f010162b2ecd624666a74e=600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 064f3d1db755c16a7e8fb51d0b847d4b670641ccd8ada7cea1ea9779e5de9e45=600960086007600660056004600360026001d37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f11bf1529932e01464f2ca2b42783b2805b74c3223cda19f8835c9664aaff6e4=600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -e5718f59f49690be6b36f5d0581b7292b6db85bf0dc6060627b0f728cef5f8d3=60003560008103604657600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +e5718f59f49690be6b36f5d0581b7292b6db85bf0dc6060627b0f728cef5f8d3=6000356000811415604757600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1217c0355376c0b2adaac7603b0c744a37dff7a4c3199a5149f1f04aab7cc5b1=600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 075a24ccb35099b1f869b1f84153341aa0cddaaf7dbc8aa1b093bb8833498e78=600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -15766aa9806a8cd8bcee26202bba40881e9e0e8a66db2a4273891512af1acd64=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +15766aa9806a8cd8bcee26202bba40881e9e0e8a66db2a4273891512af1acd64=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 72d686960fe6db035ab23e69f2adce742b03d333f2cb621d69ef03b4c22b6ffb=600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 6d29b72e08ca8356711aa2ee00c1c158beef62ea84cc170c68bf7f7eb7175e83=600960086007600660056004600360026001d47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe e14d4d4b85f8ffd1c95fa85d76010482ebc3221c9d146fd987e0be8bc601d231=600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -be8d399779cb2f1b616afb6174ba07ac61dd26cf04c3bea05f944e85666d81d4=60003560008103604657600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +be8d399779cb2f1b616afb6174ba07ac61dd26cf04c3bea05f944e85666d81d4=6000356000811415604757600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f41c0f6c76fc66275366fe14f2b8f2af35b0594a1b685ba5e78d1af61cdf98da=600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 9a38442cd0670da65eef3698a1898427c2ce78e75a1ab3e5c70b120b0b9191d0=600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -8e96e35d11f9f8532c879452f5db63f0895021bf129d206548a2c791629c4450=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +8e96e35d11f9f8532c879452f5db63f0895021bf129d206548a2c791629c4450=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 5c8ceecb04a87ff4b1c2b53ef865c0601829c40ae5f17653f39b3d936441a6e2=600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 dfb435ad82a9369f7453ba8f286b4b2e7499afd0b7ed7ef51eef7720c62a8ae6=600960086007600660056004600360026001d57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 4b6fde58d18bd57262e281bb7e9fb59ff191306e2fc0277d9e5f10a40c2091f8=600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -d3b66b44788668af78eccdbf58d84642ecff673e20b7502e1663cc431ab5d342=60003560008103604657600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +d3b66b44788668af78eccdbf58d84642ecff673e20b7502e1663cc431ab5d342=6000356000811415604757600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 163945c5a9be31f3e018865aa765df7b14b682b3a9b9f0d021d4c29a7bb28f2a=600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2aee190bd85c6b513ea8f30f27da989327d6183e568c7f7ff991152eeb2c757c=600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -f7ad6f86da09b659cfc4d9947a7cac528976d6582509b69379eda8a21b998d7a=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +f7ad6f86da09b659cfc4d9947a7cac528976d6582509b69379eda8a21b998d7a=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 875f38a3db0ca95ee896d4b699bbf0ba9d25467a71c3572a1df57a7e07607741=600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b012e1e4d422e456b576d4cbe3f81675855c26125b190073924d2f8239080d5b=600960086007600660056004600360026001d67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe ae63b4287c7620c858ac5dc37c145397a6d69612673bcd9ef45f0cdb0e7a8d17=600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -64def6d894038ace4d29e4560133253a9dc739a4e008b598d12a6fd6e3236429=60003560008103604657600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +64def6d894038ace4d29e4560133253a9dc739a4e008b598d12a6fd6e3236429=6000356000811415604757600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f4ef7077431710006a2b764b801578dcd027e2b86a6358bab4e486c92ef4685a=600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 775f19d00e1080de5f07d6846e7b51e9929ab37f6a27b7084794ab1c0f715b3e=600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -16c4d61fce0ada82ed2ec4656ab3865f8cdeefa98c7f5bf9d3fd06d8871a9419=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +16c4d61fce0ada82ed2ec4656ab3865f8cdeefa98c7f5bf9d3fd06d8871a9419=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a824e8ac73e123c5e07e5e107d2eb7abd178559b577294885c757f2f076311a9=600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c1329fe93858de8b770dcc1c7e52f7349ac7bdb8610a18207bd5ae13b341a07a=600960086007600660056004600360026001d77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe cf8c4842e4bb9ece4811336ab2c422087238a45367ba1c11e193d7346ae31065=600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -331e3b5c867cdd5aa20285b95f2398f78d0e5a68ec062acbbc89fc8286da3037=60003560008103604657600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +331e3b5c867cdd5aa20285b95f2398f78d0e5a68ec062acbbc89fc8286da3037=6000356000811415604757600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 94a82bf0575a00c9163b91fef857f2cfff2ecbaddcef44ea7c2ce5b6b38d9d64=600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5c0cec19f2d3ae92bdce5b5654fd8bee8044611589caccc23399cb60a6464144=600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -405255f663538275a907425bdcdb797e029036741dda74a120b29d7149dbce63=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +405255f663538275a907425bdcdb797e029036741dda74a120b29d7149dbce63=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8f8f08994f5f89ac8a9cde63b2ea1d677be283ca214089c5e0cf38fe13f4db53=600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 323f0b237c36d5cea8ac5dcf452b5f85b7ae706d87f01d7acbc46109573b3192=600960086007600660056004600360026001d87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe b36eb463bfed34c5d90ddee6c1592d4e8f93c2600bb220228b2556981449d367=600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -08978ff8d624d9ecb06071d361315d2228da3686f03af064dccec557f1db11c0=60003560008103604657600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +08978ff8d624d9ecb06071d361315d2228da3686f03af064dccec557f1db11c0=6000356000811415604757600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 6c36283664f46e81235d3afad69072c43635e31c46794fbb3474f28078eb5793=600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ac6d8178f43cd0a6d05514c5e3af50ce7ddd3333535fba9910632b863fd8bf43=600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c724c311074c9a2ee54976e99d4ae0ce19897de982f1b5187a9cac58c25bf716=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c724c311074c9a2ee54976e99d4ae0ce19897de982f1b5187a9cac58c25bf716=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 69ec86bbdd4ade4070a50f6872983f5b59ae4333942d075b96995cbc94568e65=600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 ec0cd2b30d45a55c363acd904e6dcde544e5cd7eea4309392e9911f45e33007a=600960086007600660056004600360026001d97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 30bd6becf598597a96536d8eed93f9ef5644fb05954af3fdd072867adebbe13b=600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8d6322ba141319d9776813a3655c5f299ed3fd2fe1eae15948be78c79d4a0738=60003560008103604657600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8d6322ba141319d9776813a3655c5f299ed3fd2fe1eae15948be78c79d4a0738=6000356000811415604757600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9458b6fd43c02f02f8542d869d0834b1f04e27c4fae4624584e7ff5b4fc79052=600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 59b9f014a87bf7838def2dfcd331d91b7a0915ae0db03002c81d932ac5f15f3f=600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -3f9c76d4bbfe55059fe39bae69dbef405332254451e1d7a1c7c9de151e2a8b01=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001da7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001da7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +3f9c76d4bbfe55059fe39bae69dbef405332254451e1d7a1c7c9de151e2a8b01=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001da7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 65d8dc667146b84ee62eb1fcf2694a76dd31a27b08bc00d70407974d47ccff50=600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 fca911db6adcd2fa48c069a8353858eb2955e951b3b75157b20ed2e03846ee82=600960086007600660056004600360026001da7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 8df84a49644c995eb18520a8c5230a2d024963dc265b89ae2324a536d81147d3=600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -870634eae2549eee081ca5f11660282ef4f8069ccf71f29afbc9fe6cd6ae7da5=60003560008103604657600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +870634eae2549eee081ca5f11660282ef4f8069ccf71f29afbc9fe6cd6ae7da5=6000356000811415604757600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f631b07b0a7264219a1cc041fac7ceb62d22bb65ea09d6fc5700beca11e37d9f=600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 b16bf31ae1d6b8fa9e718acf1fb557be4eb770c6775bc2ee0932d86708ce6099=600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e8c593b5498e8afc393365076b80fe4770005e308197bfa5b323da1a66c0e150=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001db7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001db7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e8c593b5498e8afc393365076b80fe4770005e308197bfa5b323da1a66c0e150=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001db7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 c2a78dda9a8c7eb48f529d3e449d2d8b788e05265fd839764756e2c2076607e0=600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 bd03b9dbe76b449ab5fe33f92b39d9ea5a8c6a16d2c6caf2a380b1e902a80415=600960086007600660056004600360026001db7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 360a00f371f04b54bbfe13be05b8788c3e59ecfaa6881bc5e910b79c52a66307=600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -97a2c48b39d7d3a8f624dc8ce0181d677e218139d94caa6a8ae82ecc4cdab09c=60003560008103604657600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +97a2c48b39d7d3a8f624dc8ce0181d677e218139d94caa6a8ae82ecc4cdab09c=6000356000811415604757600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 cbb0cf3fbb3f5c80bc9096e3928144501943c2feabab7ff0a3a2bb9eac5bceb5=600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 71c068967993c00134b8538ed23f2b6486441267f31e0a92e0e25b3810e81497=600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -fb7689fd218372578e00ff151d993cb0ce2b792bc3acb9e37a59f55803ae4503=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001dc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001dc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +fb7689fd218372578e00ff151d993cb0ce2b792bc3acb9e37a59f55803ae4503=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001dc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 e8b398e970686741ad54f51190189e1a5ded585f482a2c2f4a697657033255de=600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 7b370d0bca923d09f516af5a322472733de1589ed6ee37b1bc73c487f425b9b9=600960086007600660056004600360026001dc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe cfd246eac675a4ceecd8074c3e5583c1990f9fcf2b6d130572c1f0907259b360=600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -b781132f17c619b2ccd714cc1622704e74ee10935fea39cb439d9415e12dfe57=60003560008103604657600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +b781132f17c619b2ccd714cc1622704e74ee10935fea39cb439d9415e12dfe57=6000356000811415604757600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 e6c8c72aa6f08fc6db5875486d607500fe965e04ee25e73df35785e576978995=600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ab28dbd529d23d84f896551e629a1915612e0745710de40eaebea1aefbd4b014=600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -160cf541e6977d5a09a2c467fbfc2e629830f54ad1b8a4c91489eb25c930b7db=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001dd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001dd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +160cf541e6977d5a09a2c467fbfc2e629830f54ad1b8a4c91489eb25c930b7db=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001dd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 2ea73f874cd7182e0b5eff43404d91593e05b89bd5db0752a0452c8586146ed0=600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b85dfb52a17799294dd49d478e9e9297de19b1b14aa7420c7bb82ed53379f2ef=600960086007600660056004600360026001dd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 8d86480db10dd96397832298544f8bdeb3007d321358b2f0aaaaab18939389a6=600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -9554b5e01a9a9f64a9b2f671630d836c3ce772d052b45d89b73fd098b8e4956b=60003560008103604657600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +9554b5e01a9a9f64a9b2f671630d836c3ce772d052b45d89b73fd098b8e4956b=6000356000811415604757600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 ae45994ab69564b9f752678823f17108f35b7c43d1ecc3c79e73d13955495deb=600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f8347065d449af9ab723ebf487760effac17d0a688f7d2d692ae4b1083d6087c=600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -fc3b1f81b4101c234f757b02963c76e321e1a19c86313f4a37c2729f36f96917=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001de7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001de7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +fc3b1f81b4101c234f757b02963c76e321e1a19c86313f4a37c2729f36f96917=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001de7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 c98b11cb7ff2d2c263c6071e3aef3949e61fd49135c9c702b5f97cfa4868b6f9=600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 99b152ba3596c620cfb81f360a2f1f13a3b67e8f79e407e04ec7b120278054e0=600960086007600660056004600360026001de7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 894f7d896c6f3f97aa74475659106e083c12f1c9485b47ba2a5a46b914750377=600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -197ace0677b5717dbe9bbb38a007d4f3d9812825b88e9a5d26d3bc6c217120e6=60003560008103604657600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +197ace0677b5717dbe9bbb38a007d4f3d9812825b88e9a5d26d3bc6c217120e6=6000356000811415604757600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 978d1bb072c242655c64bd67200292aaea8a905e434635e1ed8f7ae9b89db82e=600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 61488411be39d9c3e1e0f15dc89143aaa78839f44d32f7e9e003bd71e87c2402=600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d6466f2f27d8ca3e9b3476113929d47bff8e5f2a00a660c80f3caa990ece0cd3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001df7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001df7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d6466f2f27d8ca3e9b3476113929d47bff8e5f2a00a660c80f3caa990ece0cd3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001df7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 d8c5bbd4c907b6331666081e9482c1c0141adce57f2a250e86ae4052f79f4aec=600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 850f5e5daba158cac9a20182ac89b09b1776df7dcf2201a5ff99e176ae70885d=600960086007600660056004600360026001df7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe b585478be2d5a7a3f172740d15bdd195936eec002036b56c44fa417a42da7406=600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c88490b7609917a71bd76632e9201eec743796779723888aa6223d47f4404568=60003560008103604657600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c88490b7609917a71bd76632e9201eec743796779723888aa6223d47f4404568=6000356000811415604757600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 50d02a31714a13bad96ed7cbde3f5a7a50f12d568b29388904605f5671ed9c50=600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 c062216b1dc2fc8721c9c45646301694a0587b25a9fd9503f1b02a292fc86a1d=600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b52a33d8d4afda44273bff7efec552c32ec14abc6513da8f23aedd5bb694f58c=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b52a33d8d4afda44273bff7efec552c32ec14abc6513da8f23aedd5bb694f58c=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 0b920f1fe84b8c374a1ab93bf9aa760ae7c6806e0e2c6108f805561135365f66=600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 a2d670b4640142e018a6bd97b67b4a224d1e2cfd9d83ffca7323f1d7427760c2=600960086007600660056004600360026001e07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 71170857b67aa7ce3c99da25de12b434b19462d52c8a3869bac0131d8252f5dc=600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -838dff6d3389cc17980a9c4a11de3e5c7391e8123c802f36008101d92e2a008b=60003560008103604657600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +838dff6d3389cc17980a9c4a11de3e5c7391e8123c802f36008101d92e2a008b=6000356000811415604757600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9e712e19129b8d66e24b17d1ffc677ab6c383bdad01e9082ce2c14d52e6a7076=600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e70105ebd0e122c5ef776e26d866cde52530a8c006e3295527f3deab717c1e66=600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d8fdc37daa1e640c784d5401d6d0ca8e7de0cc2e4b29aa166df5ace2353ce82b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d8fdc37daa1e640c784d5401d6d0ca8e7de0cc2e4b29aa166df5ace2353ce82b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 15181965c3c5ef7cb70238bd725622c8fbc4377cf46f839fc1259b065d9250fc=600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 358c91b529a4ecebb28364ec1f8d99613fb9efdbf0872f1958d226e4a860912d=600960086007600660056004600360026001e17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 918ac15c8f7a5083d26993a83325ec98a4b16de9aa6a0215837275a050c6205f=600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -147142e2be4899fdd8ff9959236d1abac1e0033ed7c87b43e64ef73dcb86226b=60003560008103604657600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +147142e2be4899fdd8ff9959236d1abac1e0033ed7c87b43e64ef73dcb86226b=6000356000811415604757600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d8b9606ab675ee115b0e60b04773f5d4a2df97c5eb99a443419fc6b3e1b2e474=600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e6ce16ceb898cfa9bbc0cba76df7cc00535795959f08a5eb0c02c9fce0ea34fc=600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -1d996539b54dc4ceb0bc68671b905a148681459bbde92ba5e9e3c1c8020a407d=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +1d996539b54dc4ceb0bc68671b905a148681459bbde92ba5e9e3c1c8020a407d=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f43f03e7ed78f6e2bfb5a70c6ade85dadf46d6c91afe7e60b2272df4e4aab3ca=600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 748ff30f8c474d41e87de746de6037d7d9d826eca2b7ecfa80c98fc8e6466b1c=600960086007600660056004600360026001e27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 90f9c8ed5b164c21fe987d8145eba63e508302a173df32caf5bc8a463fceda63=600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8c4e34bc2e6dc2f06a18b86f33ff5fd536cd7ce3f50493b5efc56f91e63b3ad2=60003560008103604657600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8c4e34bc2e6dc2f06a18b86f33ff5fd536cd7ce3f50493b5efc56f91e63b3ad2=6000356000811415604757600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 2ef23e24840908e28f272d4c7f173528c3570840129b69c795879c61310015ac=600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2a5ebcc50b0e976a4ab894984c5a6dae8b8ea71ef0625047d15c4cdbb7866be6=600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -5d948400df239177e455905eba8f51f32b0f5e5e69b68e244b8fcffa8703145c=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +5d948400df239177e455905eba8f51f32b0f5e5e69b68e244b8fcffa8703145c=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 7184f958970c18d7adfb10b2ec2b601452aa1131c2b21ec877b0c5ebd7f51633=600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 7804a58e973d93c54d03faedc926895199fbfd19e9461eb229e0da36afa3042d=600960086007600660056004600360026001e37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 1a63c5fdb5fae8d3416f1243245bf1231abfb8c558d8509b76d915292c27f6b9=600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -4d248672a92e38f633896e9e5bf15c772fa582fe5ca04dbc81d771a60bed395f=60003560008103604657600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +4d248672a92e38f633896e9e5bf15c772fa582fe5ca04dbc81d771a60bed395f=6000356000811415604757600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f4b9860f730ac0ce4cdd628b4a68d77127144da2d6336f249cd0e1028b331958=600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 004d869f75d3113eb4b1a8b5c3282f1ccf2f42d15f9708bb95ef48907fc696db=600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -8fab11955a49591336a0bce44ce64f1aa3e2ed52e8220b54a112d7bb2314126b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +8fab11955a49591336a0bce44ce64f1aa3e2ed52e8220b54a112d7bb2314126b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 1c11ba4de8f65fd6ebf6bbd4701233fff32babd9598a55a7c2274e6aff3b0bc2=600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 7262317bcd650546789641e6af1fae56fee788a8e5eb01a91073b0038a8ceadb=600960086007600660056004600360026001e47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c940dcf747770c6769d1247f2f1c4a24b376efff10320068098674d6bc55348f=600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -a60757a515fed7e4001a6c80bf5eb79662a3e2f790b5d218ace612848892d24d=60003560008103604657600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +a60757a515fed7e4001a6c80bf5eb79662a3e2f790b5d218ace612848892d24d=6000356000811415604757600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 bd43068cdf178c5141677a7dc456fe49fdd5542aa6015f895c0cae8dcfe05218=600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f949f0e895164d46b43e1fd7e6891f8487c3ba0f76e2f425586c975fee6bf23c=600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c204db0c59faaea7e9626de3a05dc08fd7c77bbf3f912264526c4a202f7df095=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c204db0c59faaea7e9626de3a05dc08fd7c77bbf3f912264526c4a202f7df095=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 92b4f61420d40e50c74aeea4079577f930e1fe9c93c6ff3b6917c0a63f60002a=600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 a01cdfb37dfffb72a91d601b507b85817df2b9a0e326121e61f6b0c65cbb1ca3=600960086007600660056004600360026001e57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe bb21e9c890ae5f2f18be121ca55d570705aa54ce039be0f02e8e95414a7ee777=600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -b14413ae274483b2b02dd1b409a7648069eb31f13cff3689197ecc2e7947104a=60003560008103604657600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +b14413ae274483b2b02dd1b409a7648069eb31f13cff3689197ecc2e7947104a=6000356000811415604757600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 448dee1cdc38e696009657272efa1e2e1381bba0846b564600d465de9fad0723=600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2e738888b00adbf0f721a9ada9299e58cbc96558f847d1234d1261932abf02cf=600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -f7dfd3c51bd9bcb2ca1bdcf7bdc99d9b3de7c6962f409b46b98ad12202db9746=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +f7dfd3c51bd9bcb2ca1bdcf7bdc99d9b3de7c6962f409b46b98ad12202db9746=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 6bfc8ec98f64c2587317236f1510fbb5355a1a92fa07883db7d3f536de27a638=600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 cf403ca4444fb4d137e849c9171585d46b87d99ec538275f7e66710e6c1ffc34=600960086007600660056004600360026001e67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 770bd70777d6d9f6da72762abeccffc85c6ab6756e160e02712222e20306deac=600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -97c18561f3dcd2620892b7275d3db5ffd49143df436c750cf87a8ecbf4bf53fa=60003560008103604657600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +97c18561f3dcd2620892b7275d3db5ffd49143df436c750cf87a8ecbf4bf53fa=6000356000811415604757600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 0b24158a59c86d19c78373b88e3161ebcc1c6a0e04c549b49701cd0b0e1c5737=600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 6485b4eb21ede9bd055ea05483bdaa33254cd92105e2308e9d18fce8338d2433=600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ee071cdda683c7ceff8b9b83f1481c2180b9c3f8571cca56b91c95017b1a2116=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ee071cdda683c7ceff8b9b83f1481c2180b9c3f8571cca56b91c95017b1a2116=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 4c7afa2c891225aa4c8c986c82073f08539b48e7a57ea81b79296f9eae780e0b=600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 12ac3f9b1eb1e2413e67bee48e812532cc9eb0173f52da644fc378d5d8a95e0c=600960086007600660056004600360026001e77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 30071e8db62321fc32b490e741b8fc5536f612665632c320144a36b9196a3e77=600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -02573bc0c5143d90436c8ff66ebc7f621436a6cc40278f9d9460059247811a78=60003560008103604657600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +02573bc0c5143d90436c8ff66ebc7f621436a6cc40278f9d9460059247811a78=6000356000811415604757600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 e2378fa0cb856ee48b09c7e8b0db9f52123bae9dabff49eeab4bf212166dbfd7=600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f1cd14bae66897b416e5e20ed1b50a21f7e8ee07441324ba8faa2e1bc8428d7a=600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -4c5d6782a96a8855f216b981439480744a61cb8277cd958f7440dca653b21b33=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +4c5d6782a96a8855f216b981439480744a61cb8277cd958f7440dca653b21b33=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 741179d363ca301ff2c65d4f13db04d42bdc3bf59ea5dc5e4dac1218d6a98a58=600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3c2b6934acde64f6d8588a20304a2ae2a13a6a65316ceb0dd7fb96839707a56b=600960086007600660056004600360026001e87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe be0ebce8b105dbbbbbead7c935065267c5567badd5a816c94191e634bf341887=600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -1666550ed444b24d7984ecd6191d558e7a52352344ea846b61ef4eb81ee7d194=60003560008103604657600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +1666550ed444b24d7984ecd6191d558e7a52352344ea846b61ef4eb81ee7d194=6000356000811415604757600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 fd51cabe84e080eee626fb7ff99e5e5b54254ec8a5ca28417d30e576c4f51b3a=600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f52593d3ce08e889d02ca234c7fe21a3222660b4d8eb0d7398963e896dffaf18=600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ac2a746cfe8a2238a189ca6bca3710601a315749b5c1e554ece549119658cfe3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ac2a746cfe8a2238a189ca6bca3710601a315749b5c1e554ece549119658cfe3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8cba75cd4b78afff97003cd8758eba1775b5b4809b42bfa0d17ccf460f458d09=600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 83b9da2d97405bb336b9d9e452a1e4cd5b66475bc7cf554a1a0fd76a818e8173=600960086007600660056004600360026001e97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c3eb6c19c606f2e44d7a1b6446bdb49671b49b6de924274929c866a279cd588c=600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -508cb9e9c724f7c54026bf7a66bb3f86b6ee58f3d630f5d52949ab17edcfbcb6=60003560008103604657600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +508cb9e9c724f7c54026bf7a66bb3f86b6ee58f3d630f5d52949ab17edcfbcb6=6000356000811415604757600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 fc5416739dbe5bc410d5c09a131838d69f2d872a199d8b72076fcb81cb0b0385=600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 7c5ccb1941125ae95b92319bfc5075c48bb9ab7be68b080da30616aafa66efb7=600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -1f1751da9715f59708a3bc6aedca352318984206f05550f900d15f58caecd3e2=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ea7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ea7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +1f1751da9715f59708a3bc6aedca352318984206f05550f900d15f58caecd3e2=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ea7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f675e7d0054ac2a9fd2d4041b18dad38a4dfee33b9548ef9ac3ea7dc213225fd=600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 6fc248e5fcf6149b241e47474249f34563d0615515edfdd5f009eb89a65261be=600960086007600660056004600360026001ea7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 2d2de327c12b768da69a87030c7570e2a34fa56bb9b2c992a51018a5930730b7=600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -790d409dd506e4483d1c95bdcceb0ffe7d377bd248c1024981e1eb580a074745=60003560008103604657600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +790d409dd506e4483d1c95bdcceb0ffe7d377bd248c1024981e1eb580a074745=6000356000811415604757600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 2991645d30d0f81333430b4feee3c094a02487997ed2e3c9ffe1aff72ca2e03c=600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5ad97103143eb047e9a9165cc1f11b82ecefce78db8858e3e578b9ac9999491e=600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -749aca47d178d05e3cf31550643c9ea9ec3cfc7ebb3faaaab7999a7a03616d04=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001eb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001eb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +749aca47d178d05e3cf31550643c9ea9ec3cfc7ebb3faaaab7999a7a03616d04=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001eb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 73cfbd20fb20381794fba4875c1ebe2a19f8847325bdca681a2771b885f961e3=600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 0c831cd6fac65d3e335439819f6e11e95cf63d5a55580c146ec1557ab788f918=600960086007600660056004600360026001eb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 2487f9d3459e086b2088b8fdabd90d263cf7f2321a596b53464400cacbdce974=600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -bf43887b8ccffedf3b7ad7612936bacf07c5a3ccc9cb833a50a3762c9eb92edd=60003560008103604657600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +bf43887b8ccffedf3b7ad7612936bacf07c5a3ccc9cb833a50a3762c9eb92edd=6000356000811415604757600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 4422cf00319d3c6a5c5e443a8f19a50ef85e8e599ba92fd911afda95f996c533=600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 c99c258df1e50fbd0ad72e7b1adce397df49b9325767ed2b9981d8dff580a424=600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -dac939bea3b32e80426f9b4c1a549c752872c8ddd8c0cf7d2948daab6136c466=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ec7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ec7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +dac939bea3b32e80426f9b4c1a549c752872c8ddd8c0cf7d2948daab6136c466=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ec7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 c92b7f7cf758c418b11eee606cc18a463b0090d40792e9df7518915ef1d5e5e4=600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b05952efd7dc44559e180dcd9f8258075ea0bc6b7c358e600ec13b6581919b9c=600960086007600660056004600360026001ec7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe a0f6909df33c00736528b1959c7e34244e7e3043297e09678bdcd7e644929ec9=600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -16af98e3251ea8b8e3602e4836e4fabcc6bf77a778c82049807d17b3fdf35a75=60003560008103604657600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +16af98e3251ea8b8e3602e4836e4fabcc6bf77a778c82049807d17b3fdf35a75=6000356000811415604757600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9b454404772226a5db6f7f798e465a0dcd47accf73f5d9e5fab44731d6052d51=600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e679d4e17ab1e726c6eb12146eb5dac927307db1e9e5083af9b12cc0fb1f5c70=600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -94826e1a45103e831581ac5368ffaa27627b0b466f8dc027e59eae2e2dcdeb22=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ed7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ed7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +94826e1a45103e831581ac5368ffaa27627b0b466f8dc027e59eae2e2dcdeb22=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ed7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 d557e90865d1307627e76f21aa7298c39cd0f612ea13feac9f7b540cf2df1fcf=600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 08877d272eb0c04b7bcf9fdd68f74cbcd1c9e0888aeaba02898ca2ce87bf6503=600960086007600660056004600360026001ed7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c0259ad40b8922acb3889dac1db324d0c28379ef4d375cbd48a3628359118269=600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -fac9b9c7698a12627883df0e362f966cd83abb95aa505594d7faabc40a2b4c41=60003560008103604657600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +fac9b9c7698a12627883df0e362f966cd83abb95aa505594d7faabc40a2b4c41=6000356000811415604757600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 8a18d4a7a9184f5cf6a5c3e08b77080ccc314000dbe68c5e47be5c0babb8c832=600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 200e26eb56e6656f0092ab68376777202054401a66caa6936e805ca5863af2e2=600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -5c77cf8e7cd77ecfc8e53ebd4a8801e3463e9f31462faa0f30fae5487b019f54=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ee7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ee7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +5c77cf8e7cd77ecfc8e53ebd4a8801e3463e9f31462faa0f30fae5487b019f54=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ee7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 1b8526f4a0eb15e80297bc3266c5d47d6dbf8e446f4cc25fc1012324509d29e5=600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 86a08195a2cd38e59ed66b1018861c7c253db9be50f0eccd8ce98c1e28fdc9a0=600960086007600660056004600360026001ee7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 0e8d12772c6b9ea24d72b536f7e173abc5ff5690bd03db17bf8a2bc2c18b4856=600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -d6afcfd9d082830fc0c0e212c9c6ff9347b63203119217ace3e76f3fcd803075=60003560008103604657600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +d6afcfd9d082830fc0c0e212c9c6ff9347b63203119217ace3e76f3fcd803075=6000356000811415604757600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 4188def3c908f821e7eeeda474e26783a020985f72f51d460ce6e56a8c047382=600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ea674664bb589f3b0bd3ab158f8b3190fe86ad034e9f3b74cb96db0320111057=600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ab098c91a13fa3ac0d7825c39a892b40b660fc1a26c26692d016d9e556ff7b7d=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ef7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ef7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ab098c91a13fa3ac0d7825c39a892b40b660fc1a26c26692d016d9e556ff7b7d=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ef7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a130730ce2d9bb64aad176f5548267d617949d578cc6d10708f72dd0455a6884=600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 528551b0bfdbe14e3d782f97911a7928ec8e37396374037720cafc1818e16a05=600960086007600660056004600360026001ef7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 2c27eda63c29e0eab08260e36aacfadfc6ceb28129cf27818ae300f76a213bfc=600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -54823c00c84f087d687ad203696c739d49e1a2b9e1fd265b115c1292011f79fb=60003560008103604657600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +54823c00c84f087d687ad203696c739d49e1a2b9e1fd265b115c1292011f79fb=6000356000811415604757600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 130e8f17c85252e3e5b4211fe7658c031a3e7928f8f82be4a9cdcf22036d0771=600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 149217604850d2db398de728ed7e92ac81a736ef24af6b728e3efe48c6f5580e=600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e075b85082356d2adac0e23604d8fa75476e55156fa1ff51057d10d809b28275=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001f67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001f67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e075b85082356d2adac0e23604d8fa75476e55156fa1ff51057d10d809b28275=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001f67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8e06cc3f38e5075be9fa28e8515a93cc044db9ff0d413857ab63090f1c560054=600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 551460d3811a5057532721ddbe687ae86e68e64195ba9f1a0ba6de1ffa8cb2c3=600960086007600660056004600360026001f67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 92e1a3010fb46ff1fb92d3d596064909d890d5f07877e143d912df5fe84e3c2f=600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -efca004e21c714ff1882b8704340b5ca514f095967aeeb63a1c1eb9b227cc223=60003560008103604657600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +efca004e21c714ff1882b8704340b5ca514f095967aeeb63a1c1eb9b227cc223=6000356000811415604757600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 66626bd408b53255151083f06eda987d818c85248fc091fa5f6f987b1437bce5=600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 48f7d28dca8a60ecf9c7390e24c109fa9cbac35fc25903c9961df7e0f13162ca=600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -a0886f328f015a1288ae2fa74ad076ef06b4a54ecba42e77f5b7d4ead12fee3d=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001f77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001f77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +a0886f328f015a1288ae2fa74ad076ef06b4a54ecba42e77f5b7d4ead12fee3d=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001f77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 86b2e0b1d3a7abbe8892ece62b8a3b3ac04dac2a42dab2238b4c4db47ecc54a8=600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 ac9b6e7eab17f4fb2c5ce550d16004ddc1dd585bd8f23f2efadddcb8faf62a32=600960086007600660056004600360026001f77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe d1a5d7ad17bf02e2368bd1e326414a9d1db70f57d837232f0bc0bbb94474ea8e=600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -2fab2f4022d9e68b4c9bde400ec8444f2d0987f4f56e7e3829fecbf79ff680aa=60003560008103604657600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +2fab2f4022d9e68b4c9bde400ec8444f2d0987f4f56e7e3829fecbf79ff680aa=6000356000811415604757600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 ba34d1576787716f1d1351cbcfaa4a3f206d86cc8ba8256eb36fee0e43443a3a=600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 544f89ca28f35f4a7c4ba6b89918ff27f0173750045d58551fb9c756ad42e4d5=600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -732386382ebcf1e94fa88c27bc1ca78c34fede07f54b73d84f51036ca80f03a4=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001f87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001f87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +732386382ebcf1e94fa88c27bc1ca78c34fede07f54b73d84f51036ca80f03a4=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001f87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 eaac45cae1c91ddc0cea84ecc42109eef7a432ec70bfe0ab310f5b6248c47b64=600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 7734e4759cf3f82530b97d76f06f0ec43a4ab2894ff0ee4733a6083a295b0894=600960086007600660056004600360026001f87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 84de9c38859f423edceaaca6adfbd1bba371db979512238ed1990488c1eeaa2d=600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -3b66d4f3fe8ce9ff5ea2e29c8829dca24e231020e5cc843e41b6859a475b9fdf=60003560008103604657600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +3b66d4f3fe8ce9ff5ea2e29c8829dca24e231020e5cc843e41b6859a475b9fdf=6000356000811415604757600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 764a4ba331bf7ee3cc40136347fc0bfcbbf53a2c3bc6b96d7db777a4fd8de3c9=600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 380f19f02df7665b3bca3d4ea3307dd40ace2f8eb5e1e7148f6ab9581ecf2386=600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -72dcf1e1aa56c92cf038fe889da1b7822ffe1630233703b08b6384bcbf422dac=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001f97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001f97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +72dcf1e1aa56c92cf038fe889da1b7822ffe1630233703b08b6384bcbf422dac=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001f97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 e0ab635835c12d40088b1bbba2810127fe547d24828b4f410c124d52365404da=600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 ed348aeb464344a017bb9cad3309f4d37c5bb3c6b316dfe930334f1df000ab11=600960086007600660056004600360026001f97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f71bd4bdb0866e72f6e47a2d83cf288b9f835d95f8f45a194e32e0efada535ca=600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -621388d59d36a339074b9d69c476be0f65475dce67601f723a9ba9b79b4fa608=60003560008103604657600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +621388d59d36a339074b9d69c476be0f65475dce67601f723a9ba9b79b4fa608=6000356000811415604757600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 0d8265dabeb6d9eb79896c42ee04c67afff9e48187d5adab68a4763a2a28faa9=600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 def56e3326695ace527958b3bf1a7976e8ad11b1ef353c7719b74c53bf114f4d=600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -9c0194fa50a9b8adf02dac6daf1181f8e873e5d5f9a4bc37ec6cb173fe6f84cb=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001fb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001fb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +9c0194fa50a9b8adf02dac6daf1181f8e873e5d5f9a4bc37ec6cb173fe6f84cb=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001fb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 c8b6a7bb41353a21c229fdb76b587e903155597eb5d822459d9cbd71799c126e=600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3ef1ec27d7ad72b7e812963d31b03d485ce148e671d4924f73b6eb268e9a01cb=600960086007600660056004600360026001fb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 37c262381218dbef934dd5f7dc2a9f81a6cd63fdacd6e5c53586e2ba83d01746=600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8b057a099f7b4d272da7a5208e6ab9450b9031dbbe3c2d18a90c2a8c59f5a613=60003560008103604657600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8b057a099f7b4d272da7a5208e6ab9450b9031dbbe3c2d18a90c2a8c59f5a613=6000356000811415604757600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 b087d8d8964016028417a134fa6aaf6f7041883d435986a67edffc817471cb59=600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2f2ed98d4ea262d50ad3c7e1400ed6d2462c7a4b05a71aeb0e6e780d132caa00=600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -7298454d03ba1e1a1cbf32f062e8c19b2026d0c00b91c2c2908597112acb974e=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001fc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001fc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +7298454d03ba1e1a1cbf32f062e8c19b2026d0c00b91c2c2908597112acb974e=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001fc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 16513dc959b0a2b4a245e7608771a01e6eaa750ad6fa07a9c17ef6c4b7f09968=600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 1f0d48fd4212f0451bb29d193812636f7fee3642d8dfab2e9aeef817daeff580=600960086007600660056004600360026001fc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe a6c29866c12943f819a2dc44a05ffcf8e1fa22a24589a38b14ce05e45f2cba69=600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -6e032b46774ee52a28b67cb147af38734a8fcbc4f2b0a84094eb4bededc590b9=60003560008103604657600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +6e032b46774ee52a28b67cb147af38734a8fcbc4f2b0a84094eb4bededc590b9=6000356000811415604757600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 7004cff6a85e2c30fb2f711e0986d1eddb81a650c26c31f1ed4d5bd802bf93ab=600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 05f1cb0012e6f176881117d451b9b045f242be5dc419ac3e8c336bcec0be97c5=600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -564733c13227d18244a0766222bb2a3098c3ba68e51c48dca39b7eef76927911=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001fe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001fe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +564733c13227d18244a0766222bb2a3098c3ba68e51c48dca39b7eef76927911=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001fe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 346d6fad6b517c62f2b07bfbb66c2b902a2a033bbe2b4a7bb896b692420452b4=600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 294a7c35085c0947a909e2167712861b0fdbe14f9aff6b4e0197507ee784982c=600960086007600660056004600360026001fe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3ff76d99e731d79141b5d3a53a252a8b009785a86e59d86e620799c55ef6b27c=600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -972da93271a848f9a5ee60cc17d73c56ff8db8f01f50a3e0b413f87591e70f89=60003560008103604657600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 -0fe574972cc9c19750b1f10dd6f2d9bdc5b92b04935875b2716fc6a456d18934=610200600080f0600055 -cd9646219770ab10d99b25d29215d8ef36dab77db51b67cf814e6a6dd3e2f560=615a17610200600080f5600055 +972da93271a848f9a5ee60cc17d73c56ff8db8f01f50a3e0b413f87591e70f89=6000356000811415604757600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 +0fe574972cc9c19750b1f10dd6f2d9bdc5b92b04935875b2716fc6a456d18934=61020060006000f0600055 +cd9646219770ab10d99b25d29215d8ef36dab77db51b67cf814e6a6dd3e2f560=615a1761020060006000f5600055 a8b8864fb681a19ccd2c165422f515b7f880ebe72c9e7763e395e54ef9520d2c=63deadbeef6000526101006000f3 74abd0b6773d7e56910bffd51015a816f1be85889f54357e0b94cc8da40fccc9=61beef5150 813aeb718ccb8cccdd9ff70ff394092a1012f072db8fca7637732cf38e31888d=60ff61beef52 6f4cf8175e4d21d167dfe5839411e2a9291a3d57060ebfdc79c640898daa74df=60ff61beef53 -c768c173e76aa9afafc358f1faa7a441e93dc31af52f01496d7743b21d8d9bf0=60243560443560043562c0de000160005b60008103602d5760008060008060008689f1905082840193506010565b82840360005550505050 -850489727f49e4d0fbf69f704aa27e6ae870c65eeeecaf1ee989968fa94168e5=60005b6101008110156030578060981b600080600080600085612710f115602557600182555b506001810190506002565b50600161010055 +c768c173e76aa9afafc358f1faa7a441e93dc31af52f01496d7743b21d8d9bf0=60243560443560043562c0de000160005b6000811415603157600060006000600060008689f1905082840193505b6010565b82840360005550505050 +850489727f49e4d0fbf69f704aa27e6ae870c65eeeecaf1ee989968fa94168e5=60005b6101008110156033578060981b6000600060006000600085612710f115602757600182555b505b6001810190506002565b50600161010055 6928d085b75273e089cb60e6279c2e5258b5de474c5c739efcda1d2f9e82ea5b=600060006000600060003562011170fa60015500 5384e137990f962e727fc9208c6ddae5eebed3c50907b8580f1cb88ee887d156=6001600152600160016001f060025500 3e3ca66c03e0afded22a1454fa2e937382c62708046cbdb213e599ccd49d0c08=60406000604060006000731000000000000000000000000000000000000001611770f100 @@ -1223,35 +1223,35 @@ bb647378cad07f6e87fe40bb0fe78701a9e3661a5362fa59bda7c3957db6cfb6=604060006040600 a3ca55d78a4ac1b3d171e8d3174126d734a02985e10c202967d8ced5b26adfce=6040600060406000600173100000000000000000000000000000000000000162055730f160005500 5bd15877907e4de9273ea001e7f4a96dddbe0510b3342aafecd9bdf97edeec92=604060006040600060027310000000000000000000000000000000000000026203d090f160015500 88456889c166b83101ad56e52b749cee36c47f971234d3bb2192f65909f7d3ab=600160025533600455346007553060e6553260e8553660ec553860ee553a60f05500 -8e3b63e1835877f5c7e14ae041df5e55c3e1c58425c48ee09d567c25afd345c5=6001600255622fffff60002000 -12c5b66cab03697243c3c8394e393d9ada028aa2f939a29893dd29132cb251ab=60406000604060006000731000000000000000000000000000000000000001620249f0f160005500 8ed43c0dd7c55dd8e69ca219d4e46f648a1a8822c54a706dc6827a2df2b12d26=60406000604060006000731000000000000000000000000000000000000002614e34f16001556001600b5500 -14b4e2df05d9e705d07cbe82e401ae12f456777e33684246ba685a82b999db2f=60406000604060006014731000000000000000000000000000000000000001620c3500f160005500 +12c5b66cab03697243c3c8394e393d9ada028aa2f939a29893dd29132cb251ab=60406000604060006000731000000000000000000000000000000000000001620249f0f160005500 +8e3b63e1835877f5c7e14ae041df5e55c3e1c58425c48ee09d567c25afd345c5=6001600255622fffff60002000 b77a8cb081a384fefe0b039719a385c5e7826d5fdb3503cda50dcb1169f029ed=6040600060406000600a731000000000000000000000000000000000000002620927c0f16001556001600b5500 -0e02fd4a9d353d6f8b41c307719a12a96d40df3a8017deb600b3be18a9815da1=6040600060406000600073100000000000000000000000000000000000000261c350f1600155731000000000000000000000000000000000000000ff00 +14b4e2df05d9e705d07cbe82e401ae12f456777e33684246ba685a82b999db2f=60406000604060006014731000000000000000000000000000000000000001620c3500f160005500 f07eabab66fdff9b2221467aa50e4adb2fa9752be1569992c09b58afc9186fde=600160025500 -cb98cd24b0233d3b9df91efc03eb40eb74fa5fda19002137f3c3b2fd828e069c=60406000604060006002731000000000000000000000000000000000000002620493e0f160015500 -cd28eb7e8e982cc57daf0ebef75bb87c5a1db046d0d0807ebd05bde76a3e12da=604060006040600060037310000000000000000000000000000000000000036203d090f160025500 +0e02fd4a9d353d6f8b41c307719a12a96d40df3a8017deb600b3be18a9815da1=6040600060406000600073100000000000000000000000000000000000000261c350f1600155731000000000000000000000000000000000000000ff00 7813f04a6d80c2325ce2651c237631d8e8a4afc30418ed83cdcaf7e6579969d2=600160035533600455346007553061014a553261014c55366101505538610152553a6101545500 -8b918c7081972ad7b1410972e6a04b99afeda6e9b41f30b5e7b5e360f2196b6e=6040600060406000600073100000000000000000000000000000000000000362061a80f16002556001600b5500 +cd28eb7e8e982cc57daf0ebef75bb87c5a1db046d0d0807ebd05bde76a3e12da=604060006040600060037310000000000000000000000000000000000000036203d090f160025500 +cb98cd24b0233d3b9df91efc03eb40eb74fa5fda19002137f3c3b2fd828e069c=60406000604060006002731000000000000000000000000000000000000002620493e0f160015500 +3577c21f368308f65d37ab7fd52ca073e89f8de1acbed04abac4b9f3d6093e4f=60406000604060006000731000000000000000000000000000000000000002620927c0f160015500 f2cdbcd1dc78c4f263d22b40356f172af8a68747e742ef5412a84aa63f620353=60406000604060006000731000000000000000000000000000000000000001620c3500f160005500 +8b918c7081972ad7b1410972e6a04b99afeda6e9b41f30b5e7b5e360f2196b6e=6040600060406000600073100000000000000000000000000000000000000362061a80f16002556001600b5500 3c8f41896e16cadb4206f2d760dd083207e2735bc8e9e240aa41a2cc6163af37=6001600355622fffff60002000 -3577c21f368308f65d37ab7fd52ca073e89f8de1acbed04abac4b9f3d6093e4f=60406000604060006000731000000000000000000000000000000000000002620927c0f160015500 +f5c742a5ab1925c82083c4dee955d0c814e53920968aa92b59b0c8d1fcdeb360=60406000604060006000731000000000000000000000000000000000000002620927c0f1600155622fffff60002000 c954d7752af9bb6b359ec69b4f1b7b5d8496b1b1c7a5e5eb1bf0e5ce1b08a0ad=6040600060406000600073100000000000000000000000000000000000000362061a80f160025500 c43df18b56f764adfe86e2d2a48e33b927d48bed4522c2aabe28115c550e4838=60406000604060006000731000000000000000000000000000000000000001620c3500f16000556001600b5500 -f5c742a5ab1925c82083c4dee955d0c814e53920968aa92b59b0c8d1fcdeb360=60406000604060006000731000000000000000000000000000000000000002620927c0f1600155622fffff60002000 ce2a353f90f2d01731989db0ecffe7d87aaf7a4fef740d3450d85d46e9c2c6f5=600160035500 -79e1d0c4625fa2858058c76337db79abc512f3eee48e7350ddcc566944b59240=622fffff600020506040600060406000600073100000000000000000000000000000000000000362061a80f160025500 7bccf87f855ed3aa795c0985150e4c4f002eb570aa34a94ab98e7136a194e4c4=60406000604060006000731000000000000000000000000000000000000002620927c0f16001556001600b5500 +79e1d0c4625fa2858058c76337db79abc512f3eee48e7350ddcc566944b59240=622fffff600020506040600060406000600073100000000000000000000000000000000000000362061a80f160025500 67b61ae1d5635fbd4412ec9b2c60a1418a290151e86ab16c497ec6acd8a79a9a=6040600060406000600073100000000000000000000000000000000000000361c350f1600255731000000000000000000000000000000000000001ff00 d9062174eb6c02dc75092567cdb85a07d131f321f6233583c1aca93c7ea8b771=600160035500 c4b27aecda668677fbf62f8e3015c4456eb92e4d6cb80501135c8e8b5efafd62=60406000604060006000731000000000000000000000000000000000000002620186a0f160015500 1a243e537a1f1194ca38645e48c62d8772c1e0f3d18d80e49ef32b6704765a89=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f160025500 75b5d0815b5a203505379176aa93a9b92f4991c54ec9bcb3a920c822926a4b9d=6040600060406000600073100000000000000000000000000000000000000163017d7840f160005500 -f72666efbda95799975b0e9fb2cd7271b921758f61f87fb96f8ecb79498b074c=604060006040600060007310000000000000000000000000000000000000016207a120f160025500 e31f2dd3719ab6b5665d781a415fb9676b6d8564f72b34cbe2e62a14f12fced6=60406000604060006000731000000000000000000000000000000000000002620f4240f160015500 -f8b7a672693c1238a852f75319baa0ebddcbfb7f1ed66a9be6df5eb9b4e64ab0=604060006040600060037310000000000000000000000000000000000000036203d090f260025500 +f72666efbda95799975b0e9fb2cd7271b921758f61f87fb96f8ecb79498b074c=604060006040600060007310000000000000000000000000000000000000016207a120f160025500 b51f7a5fde1b616abd9108bd69188022c9a3a8ecdb2cc1b10fbe56c2de4a547b=600160035533600455346007553061014a553261014c55366101505538610152553a6101545500 +f8b7a672693c1238a852f75319baa0ebddcbfb7f1ed66a9be6df5eb9b4e64ab0=604060006040600060037310000000000000000000000000000000000000036203d090f260025500 aab9b0b3c96ec228ad35203f938704da71856552d8ccd462c32b6763888eff32=6040600060406000600073100000000000000000000000000000000000000362061a80f26002556001600b5500 582f7d4a96ae68d119e55d4fdc233b684112f32b6fa159d3351c2956441d4505=6040600060406000600073100000000000000000000000000000000000000362061a80f260025500 f569a9205c64a5ad90f7dd19e0512767f3f6478684369fe213b0a061ed0a5195=60406000604060006000731000000000000000000000000000000000000001620c3500f16000556001600b5500 @@ -1259,13 +1259,13 @@ c2cb4e1d0e625267431eacd607318205bf668542f75b3abe0e905b890626bb58=622fffff6000205 67e0d65e01b31402a90c27c2af74793dfe4bbdfa25f98618697cdec5b204f0d0=6040600060406000600073100000000000000000000000000000000000000361c350f2600255731000000000000000000000000000000000000001ff00 074806ed0f72c17fd378df530017b5188388d55a86ccb184acad1e1e78a6445a=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f260025500 afd2261368d666cf7edd2b4d148257839c388eef0ac93bae452fd120fe65bac5=604060006040600060007310000000000000000000000000000000000000016207a120f260025500 -46357373e108cf8881d0cf14866ef5217ab6247fc4c2d7c833c348bc2d4d3a1f=600160025533600455346007553060e6553260e8553660ec553860ee553a60f05500 cbc8787a9c2f2999deac8496bc4c0fce7586384b86a424e3db005b59887af28e=604060006040600060027310000000000000000000000000000000000000026203d090f260015500 +46357373e108cf8881d0cf14866ef5217ab6247fc4c2d7c833c348bc2d4d3a1f=600160025533600455346007553060e6553260e8553660ec553860ee553a60f05500 8fdee024b6e02a1555f973f0696ac1f8c3cd356288ad1a8e1610e1b882911fc6=60406000604060006000731000000000000000000000000000000000000002620927c0f26001556001600b5500 3b0b8cc8d5b61e73b2a4205b62239de5b6a4ecd1167b14931702c464f7cde9c0=6040600060406000600073100000000000000000000000000000000000000261c350f2600155731000000000000000000000000000000000000000ff00 10aa98a2c518f4fedfc8d64915d777c8f8d3a67766355befca05f91d48b37df1=60406000604060006002731000000000000000000000000000000000000002620493e0f260015500 -58836a1be02c5e300cf41ab746d3d83083d734a3e2258425897bc248a78aa49d=6040600060406000600073100000000000000000000000000000000000000362061a80f16002556001600b5500 5fa60e5a81aa2b8ad7c733a64c9c49b86c5c9b525bbf8115a44321b4e4a53051=60406000604060006000731000000000000000000000000000000000000002620927c0f260015500 +58836a1be02c5e300cf41ab746d3d83083d734a3e2258425897bc248a78aa49d=6040600060406000600073100000000000000000000000000000000000000362061a80f16002556001600b5500 0efc3763ee86b2084d202698b0e7f67965a1d9c699ca5a473e1b74eaff702d17=60406000604060006000731000000000000000000000000000000000000002620927c0f2600155622fffff60002000 dc572586bef4a8aaeddeca7bdb4a2fb22aea11e73c3a0c8257922ad35da9ba48=60406000604060006000731000000000000000000000000000000000000002620186a0f260015500 5eeff94fbf1224f83abf924923d427f2c5117e826dc41d97eb722afcb98d7861=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f160025500 @@ -1275,24 +1275,24 @@ f73554dec3a16f0e74e40e1024a0ef5ec5d54e5031b36135bc5a29dd18a3fe9e=604060006040600 5c4c27068d91a4bc0a509b062587e32c76d219f8c6383de4618a5083a54b9b5a=622fffff600020506040600060406000600073100000000000000000000000000000000000000362061a80f260025500 046362e811154a462291783b0bce2d041eebd98be82f44a641ee7841b0149a06=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f260025500 5c4e4211d31ab5f57365c6e4c7984034fd67bba3f8fdc2d8b619ad44f84a6785=604680602760003960006000f0600a5560406000604060006000600a54620186a0f2600b5500fe604060006040600060007313136008b64ff592819b2fa6d43f2835c452020e620186a0f2607a5560128060346000396000f300fe600160005530601455326015553360165500 -ffb08aeffbd9b520533cfc3c107a95d2a60ae17609070190257a7cc3c3a3162c=7f604060006040600060007313136008b64ff592819b2fa6d43f2835c452020e626000527f0186a0f2600b5533600c55000000000000000000000000000000000000000000602052604060006001f000 0781c07e53700dd3d72727c8b2debce4508ab04080c0f18a391d94ee9a6354ad=60006000600060006000600035620c3500f100 -e8b1ae01b050389d43a28f95b9772586231d88a54f96a951174feb63ed78d6e5=6000601f80602960003960006000f5600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 -a1600b2bec3bcf1f10142fd2693965b831337028896de7a65b0ec5e3c1b05485=601f80602760003960006000f0600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 -9317b5ce007832961b43b36beec35b6eb98061807bb791ba6a57599a48c50422=604680600f60003960006000f000fe601f80602760003960006000f0600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 +ffb08aeffbd9b520533cfc3c107a95d2a60ae17609070190257a7cc3c3a3162c=7f604060006040600060007313136008b64ff592819b2fa6d43f2835c452020e626000527f0186a0f2600b5533600c55000000000000000000000000000000000000000000602052604060006001f000 b632e6ffcaeaba9e194657cee1302cad3b6f20080074d6b676eec1c3ce52830c=604880600f60003960006000f000fe6000601f80602960003960006000f5600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 +9317b5ce007832961b43b36beec35b6eb98061807bb791ba6a57599a48c50422=604680600f60003960006000f000fe601f80602760003960006000f0600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 +a1600b2bec3bcf1f10142fd2693965b831337028896de7a65b0ec5e3c1b05485=601f80602760003960006000f0600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 +e8b1ae01b050389d43a28f95b9772586231d88a54f96a951174feb63ed78d6e5=6000601f80602960003960006000f5600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 17a17bdfd8ed20c2d05b070e39b9860be846caecdb1a6c1593d5e4de63d001a2=60406000604060006103e873945304eb96065b2a98b57a48a06ae28d285a71b561c350f260005500 -61100d03e6bc8e21007b967394c28070e1a33b8251653d33f33bc844f795e18c=602d80600f60003960006000f000fe600060006000600060017310000000000000000000000000000000000000016207a120f2600155600160025500 -9ac432d14151579f379e6c6ef6603dba2c74f9ca0b72aa1ddd8ab6b447e588b0=60006000600060006000600035620493e0f100 b43dc61de74fe6a4953f2906b071ec1438c398373f3a9698f1fe18aa0978264a=6000602d80601160003960006000f500fe600060006000600060017310000000000000000000000000000000000000016207a120f2600155600160025500 -d4cc8a95f1e80db2ba9a385019262bab72dad70d36552b7ce4eeb2af6a255c7f=600160025500 -3e66e2480ca9e491f8eda2b3fea9454f246a77f7230c37b0f00ec43bac018405=6000602880601160003960006000f500fe600060006000600060017310000000000000000000000000000000000000016207a120f260015500 +9ac432d14151579f379e6c6ef6603dba2c74f9ca0b72aa1ddd8ab6b447e588b0=60006000600060006000600035620493e0f100 +61100d03e6bc8e21007b967394c28070e1a33b8251653d33f33bc844f795e18c=602d80600f60003960006000f000fe600060006000600060017310000000000000000000000000000000000000016207a120f2600155600160025500 9d0234cabda87e4cee52a8399e41e5d14a66ea152f45ff4cbc3f28b0ed90afc7=602880600f60003960006000f000fe600060006000600060017310000000000000000000000000000000000000016207a120f260015500 +3e66e2480ca9e491f8eda2b3fea9454f246a77f7230c37b0f00ec43bac018405=6000602880601160003960006000f500fe600060006000600060017310000000000000000000000000000000000000016207a120f260015500 +d4cc8a95f1e80db2ba9a385019262bab72dad70d36552b7ce4eeb2af6a255c7f=600160025500 c26c1be026f10f7967f44e293e60a5f0792a00930b69ea74b536e6a95f46817a=6000602780601160003960006001f500fe6000600060006000600173100000000000000000000000000000000000000161c350f260015500 3055ea3fb0023a093dc69ca6f68d42a1bf1f4aeb9e72345bc724cc1fde2f99d3=602780600f60003960006001f000fe6000600060006000600173100000000000000000000000000000000000000161c350f260015500 b574c885f9a99c244236f9e0cff1c5f8a6384b7a5a12e193dd4c2470779b7801=7f6040600060406000600573945304eb96065b2a98b57a48a06ae28d285a71b5626000527f0186a0f260005500000000000000000000000000000000000000000000000000602052604060006005f000 -c1fb2cafa472d25b2e701f98e55b581704134654e4acb7b37071cc4dee227d02=600160005500 d8afdb839931d006b01476af545bf36e997c21212cd1080ec45b76fb7a401349=60406000604060006000731000000000000000000000000000000000000001620f4240f1505860035500 +c1fb2cafa472d25b2e701f98e55b581704134654e4acb7b37071cc4dee227d02=600160005500 f5aa71ba0105c50bf66641dcc2b61db2716a975af14270bfd4c1d68caeb95878=6040600060406000600173100000000000000000000000000000000000000162055730f260005500 b49f13774260617e36de55306ef58d53dbb960c90296f87df1945e7f12290af4=60406000604060006000731000000000000000000000000000000000000001620c3500f260005500 8aae40196db54fe83f59c904358d7f2652a28e9d91956a345078f6a9dad2a812=60406000604060006000731000000000000000000000000000000000000001620249f0f260005500 @@ -1321,8 +1321,8 @@ edb1554eb88f7baca78e288b2899cf55561b38fbf961e7c307911564f1511a52=7f5e20a0453cecd ba13a823bdd4269bd02e87eeeaf8af71c03171c5e51ef3080cc3ab5818ddbfb4=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600a600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d87620249f0f15060005160005500 9666a182ca2a743f281ec8466180532d04b0262e95b4d2c58d998728ee2a36bd=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600260006040600068056bc75e2d6310000073945304eb96065b2a98b57a48a06ae28d285a71b56bfffffffffffffffffffffffff160005560005160015500 51450a8f66a7c8770c21f5d79b35fe3c98091e94540a41f80b3a087aecd9f20b=6000600060006000620186a173945304eb96065b2a98b57a48a06ae28d285a71b5622dc6c1f160005500 -d17813a18f145ef8682b4c40342acfb5287063595493be309cc9984189443a8b=600160025500 33251d4eb0ed54b567a8771e520308d222c42ca134974159a2ae5c45845c1dc6=6002600060406000670de0b6b3a764000173945304eb96065b2a98b57a48a06ae28d285a71b5620249f0f160005500 +d17813a18f145ef8682b4c40342acfb5287063595493be309cc9984189443a8b=600160025500 b6907b94d070d2947662ab7e7598594c4b4bb454df640bb9930390e22a653d99=60016000600060006000670de0b6b3a764000073945304eb96065b2a98b57a48a06ae28d285a71b5612710f10160005500 4bcdd059d6818774f0d404da5955423dade2461920da3e71eb4bc9e598c0fefc=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b66000526000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d87620249f0f25060005160005500 6a37834b53b708e0e94116d0ce4e0350aa7355254971dfae93d3855825528782=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b66000526000600060206000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350f25060005160005500 @@ -1340,15 +1340,15 @@ ec694004735c0b522f8a9f6fd5180a9c2494247b555610be80fdc4d75b2500ac=605660005360016 6e11f3e395588cc86b63e3c2b2516f87b48c6bdb06b08687133485406879f9f4=7f6103ff6000525b7f0102030405060708090a0102030405060708090a010203046000527f05060708090a0102600160005103600052600051600657000000000000000000602052604060006001f0ff00 c137a7179c74a03d14fd503f963426b55c96d8bf1cbdc9ad3d1a36cf802d0f24=6001600053600160006001f0ff00 a32a49add76b1a0489253be706b5e8dab6df23601f8b163137f9357c99706ea7=60f4600053600160006001f0ff00 +84ce02ddd7aaf18251de022973d16da57a66afb8540bc8ac823d150f61f04580=60f9600053600160006001f0ff00 aee27f8ef4805828008cb931a22fcfdc7b29f5fa6cb059fafbde54ee908bffe3=6000600060006000600073100000000000000000000000000000000000000062061a80f16000556000600060006000600073200000000000000000000000000000000000000062061a80f1600155600160025500 746af2369d7b396e4bd872828720e3ee44a32ddc257a721d6b9fa6d15674d952=60f96000536000600160006001f5ff00 -84ce02ddd7aaf18251de022973d16da57a66afb8540bc8ac823d150f61f04580=60f9600053600160006001f0ff00 f2be3b0fb39e23bdb60c9755a02f1abd00f5dbbf3e9a9ecf28b723de274ea981=600d80600f60003960006001f000fe6001600155622fffff60002000 3cc19bd67be0e03b590c3914a7888fc7bfe26f68890764c19dcc5446a5fa0e23=605a600053600160006001f0ff00 f49c3ea625a65ef58ed794f61b60b0ae0b0cb7350dcea10506dca6a7046603fd=7f6001600155601080600c6000396000f3006000355415600957005b602035600060005260356020536055602153602260006017f000 240cceee43253699aea20e3e83707e9cd84da2a18e53d9b801886906fac74b24=7c601080600c6000396000f3006000355415600957005b60203560003555600052601d6003670de0b6b3a7640001f060005500 -398cd6796959872c403ed50ad5d3dbebe0a99c5e0fc2842540e7afdc024bb2a2=600160035533600455346005553061014a553261014c55366101505538610152553a6101545500 51d10086c257a98329b0add6e29cb76177d582c784780c9bc85d46094a267d2b=60406000604060007310000000000000000000000000000000000000036203d090f460025500 +398cd6796959872c403ed50ad5d3dbebe0a99c5e0fc2842540e7afdc024bb2a2=600160035533600455346005553061014a553261014c55366101505538610152553a6101545500 1af2def18495e5fa4ad47ed64ba29d322587f9ae8ae842697c3f9eb782943812=604060006040600073100000000000000000000000000000000000000362061a80f46002556001600b5500 f29f2b9f024abf0877bf09b16d0f902378512cdb21351f2cafdb3221b8e98355=60406000604060006000731000000000000000000000000000000000000001620c3500f26000556001600b5500 02a99c1e93cd900f2936fcc2847d8104318e36af498a1b45d2552faf8be77064=604060006040600073100000000000000000000000000000000000000362061a80f460025500 @@ -1360,9 +1360,9 @@ c0f7ed0d8e02ed57c41436dab38b36ad26350dba91ca4f37c58ea8437ed57dc7=604060006040600 cf702121818e2231130dd688ad9f774dc418a4cb117b62958855ef7b71a217e3=600160025533600455346005553060e6553260e8553660ec553860ee553a60f05500 159206c712451985f130b9eca80a8383d0011c8de790db7be4ce55e5d1bda864=6040600060406000731000000000000000000000000000000000000002620927c0f46001556001600b5500 c35f50164dd0b05b29e015b62358a090ea77f334fe41aa8f97da6034f9e8c305=604060006040600073100000000000000000000000000000000000000261c350f4600155731000000000000000000000000000000000000000ff00 -88eab4bd2174b26ebbf11ef85aff5de1c77e79292004dee2ea85e6a00d566c7a=6040600060406000731000000000000000000000000000000000000002620493e0f460015500 -2ad9bcd6417058afe68fdaa03098e2b5acf03dc1fca6c59b2a737a8ed698059b=604060006040600060027310000000000000000000000000000000000000036203d090f26002553360055500 d2095106e49e36d21f7392fedf4690153d3ebda1654e56ffa1a4fc2201abc429=600160035533600455346006553061014a553261014c55366101505538610152553a6101545500 +2ad9bcd6417058afe68fdaa03098e2b5acf03dc1fca6c59b2a737a8ed698059b=604060006040600060027310000000000000000000000000000000000000036203d090f26002553360055500 +88eab4bd2174b26ebbf11ef85aff5de1c77e79292004dee2ea85e6a00d566c7a=6040600060406000731000000000000000000000000000000000000002620493e0f460015500 d7d9ebb58870cae24949ef5e9077cb1d7f4f86b93fc7e76370c2c0855c158156=6040600060406000731000000000000000000000000000000000000002620927c0f460015500 3a0c79acef60d052ce3524576eec73bb49573b7b0d96dc31811a4dbecbf8727a=6040600060406000731000000000000000000000000000000000000002620927c0f4600155622fffff60002000 47b71b42a05f88499a250e5d3d0cc183b251591d277615c440f59f24d2354d5c=6040600060406000731000000000000000000000000000000000000002620186a0f460015500 @@ -1375,9 +1375,9 @@ b512dd9e6d8c4407956a32fb9b294ffe741000025a2a30b6d95443ec4d794fba=731000000000000 f80639dcae440a5f3755817c73200108d10346d1b2a1ec462d3c64baf147be39=604060006040600073100000000000000000000000000000000000000162055730f460005500 104c137733c8008766e33f46ed1ca976a471001b1acd32fb8ae21c0d6a2b3966=6040600060406000731000000000000000000000000000000000000001620c3500f460005500 a0d6cac9b13007bde698284e9d71776d04aeb0e83af14f6471178303416e13c7=6040600060406000731000000000000000000000000000000000000001620249f0f460005500 -d20b8c7aac7af042709438df0c55c9eb4a0c76ed138feebad265a24d4dd108a9=604060006040600060027310000000000000000000000000000000000000036203d090f260025500 3a7e5951bd41fe60f89934b73f2f9feacd129886a864bebaa310f008cd6ba7c1=60406000604060006001731000000000000000000000000000000000000002620493e0f26001553360055500 57254510d94ba0bb062a4c74cfbcac305796ebb501a9e8a0eaeb0d1e8b974532=600160035533600455346006553061014a553261014c55366101505538610152553a6101545500 +d20b8c7aac7af042709438df0c55c9eb4a0c76ed138feebad265a24d4dd108a9=604060006040600060027310000000000000000000000000000000000000036203d090f260025500 0d33be7d29a18dfbea4bb5ed93a8c5ab3e109aaa0f7cbaf62a823063be027318=6001600355622fffff60002000 05d1fdcfa91cc161f56f0552e0ef4f4dfed7c9d8d4ccb4f56c91ef3858704d7a=6040600060406000731000000000000000000000000000000000000001620c3500f46000556001600b5500 cbc141ccec0aab609b060af8b39c0d2895341cf79d14d369737d5922297aa13c=604060006040600073100000000000000000000000000000000000000163017d7840f460005500 @@ -1395,10 +1395,10 @@ a0d25ad83bce8d5ccc1266a7390006c141f50d55dbfa58ccaf97c9279f5f3f95=604060006040600 a5f9917621aa3c9aa7a9960bc14036a51d86172218f77e1a67eea6c8fffb02a8=6040600060406000731000000000000000000000000000000000000002620927c0f46001556001600b5500 4d64baf66cc6d9d0dd3475fd3615b39a15308a74f19d1a2850cba310a3397aa9=604060006040600060027310000000000000000000000000000000000000036203d090f16002553360055500 7393600193654230e2045d30a614f74a499650cc202a7439cdaf0db78f67b701=6040600060406000731000000000000000000000000000000000000002620927c0f46001556001600b5500 -1edb4454c5c39aa6e23260046157dba37e2b48f7a37cd1fa2f5c3768ac16f235=600160025533600455346007553060e6553260e8553660ec553860ee553a60f05500 2a8c48db3cd48b654c4826fb06db713f48123aac882693cc5461d82fabe81ee7=604060006040600060017310000000000000000000000000000000000000026203d090f160015500 -4a30d44b30c21f2b3213ebc5549ee0253178486a874ba9c9afdc3f999c1ca120=604060006040600060027310000000000000000000000000000000000000036203d090f160025500 +1edb4454c5c39aa6e23260046157dba37e2b48f7a37cd1fa2f5c3768ac16f235=600160025533600455346007553060e6553260e8553660ec553860ee553a60f05500 e4d99bb09a1622904a65f60c72b1c9ef57ee9e92738b91977d4bfaa645ee07f8=60406000604060006001731000000000000000000000000000000000000002620493e0f16001553360055500 +4a30d44b30c21f2b3213ebc5549ee0253178486a874ba9c9afdc3f999c1ca120=604060006040600060027310000000000000000000000000000000000000036203d090f160025500 832b3f9c132356394daddb9475fa7914249bf41fa567c1e91835050db6a7f2b0=60406000604060006001731000000000000000000000000000000000000002620493e0f16001553360055500 937af60a3bbebb327cccf02e219a1c9e91a927555238869c6e41f5cb8c275fd7=622fffff60002050604060006040600073100000000000000000000000000000000000000362061a80f460025500 4ba903617e999dc3428cdb258fecfdf2b29dcc9c8b42f173da4f1957fb3df070=604060006040600060017310000000000000000000000000000000000000036203d090f16002553360065500 @@ -1406,21 +1406,21 @@ e4d99bb09a1622904a65f60c72b1c9ef57ee9e92738b91977d4bfaa645ee07f8=604060006040600 d6f6c2b3d15ea8de99213966d762fb488bd20a2c536de50bd5add1d342b25960=61123460205260406000600073eeef5374fce5edbc8e2a8697c15331677e6ebf0b3c60005160005560205160015561567860605260406000604073a94f5374fce5edbc8e2a8697c15331677e6ebf0b3c60405160025560605160035500 8a4cd2fde1ab95e5f6b7f1d175682bf9393eec6878449795d82777be9d1b7673=6002600a600173bbbf5374fce5edbc8e2a8697c15331677e6ebf0b3c6000516002556002600a600173cccf5374fce5edbc8e2a8697c15331677e6ebf0b3c6000516003556002600a600173dddf5374fce5edbc8e2a8697c15331677e6ebf0b3c6000516004556002600a600173eeef5374fce5edbc8e2a8697c15331677e6ebf0b3c60005160055560c8600a600173eeef5374fce5edbc8e2a8697c15331677e6ebf0b3c60005160065500 a26bb885494e0b85f27e61d59f8f645aeaea0a42b03b4d6f2c9e327989f55816=38600155303b60025500 -43a2044718bbc63caf58b8787e580d53758357db8f9a1dd83f6dec4fd5ebda3a=600035600052600036600080f560005560018055 +43a2044718bbc63caf58b8787e580d53758357db8f9a1dd83f6dec4fd5ebda3a=60003560005260003660006000f56000556001600155 b3ae2ca19746076634f6ce2073cefb64cdc7ae3dd306639840eebdb9ea882f00=6160006000f3 c44968378b56fe928db69677e9f50d18fdf6ae558b6afa25ecb473ab38558d23=6160016000f3 -58cb5fb86ad9d15449738047d3b636c8da84305fc0085d159588788c8ed9cb49=60003560005236600080f060005560018055 +58cb5fb86ad9d15449738047d3b636c8da84305fc0085d159588788c8ed9cb49=6000356000523660006000f06000556001600155 cfaef2ef539e024c4a5185c0fe50c2b333446e676879766168f4b431aab1e270=7f6001600155601080600c6000396000f3006000355415600957005b602035600060005260356020536055602153600063ffffffff60006001f500 08b8b52cb0c8acbc1f7d3c022b73b922d06daf308e69a669c03e22243c29f902=7f6001600155601080600c6000396000f3006000355415600957005b602035600060005260356020536055602153600067ffffffffffffffff60006001f55060006fffffffffffffffffffffffffffffffff60006001f55060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60006001f55060006000630fffffff6001f5506000600063ffffffff6001f5506000600067ffffffffffffffff6001f550600060006fffffffffffffffffffffffffffffffff6001f550600060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001f5506000630fffffff630fffffff6001f550600063ffffffff63ffffffff6001f550600067ffffffffffffffff67ffffffffffffffff6001f55060006fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6001f55060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001f500 56e90a040e5942ed41cb57aba0bb88d80496b2b3ee5c224561348017daf29891=7f6001600155601080600c6000396000f3006000355415600957005b6020356000600052603560205360556021536000600060006001f5506000630fffffff60006001f500 215a6b4634450b670cf51948a4ac6bbcc02b064a7effdad6d09d895a704498d8=6020600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b620249f0f15060005160015500 a0bd887cab26482b2eae42e58c3b25ec2363925901e1c69ea890b43448bb929b=746d64600c6000556000526005601bf36000526001ff60005260006015600b6001f550600b600055600e6012f300 -52227e17d7647fe54dafe44b4deb62e226a5128df5abeb56b567d38dad4d665a=600035600052600036600080f5600055 -eab3f419be128f0744b8ff553eac239abd0fa8010eb15c6e908c6906a6bf9206=7f600060005360016000f30000000000000000000000000000000000000000000060005260005b610100811015604d57806001536000600a600080f5604357600181555b6001810190506026565b50600161010055 -99f533052ff998814398779b29eb17d1d9cda70c84a1c5c8de62d89afc739ba9=60003561ffff54706005600c60003960056000f360016001556000526000808303602f576011806020036000f090505b60018303604357816011806020036000f590505b8060025560008111156058576001820161ffff555b8060005260206000f3 -aa230d92a57b6ac334b54c9a345753a57bd824c1e86bdae7d5afb69ad0b40db7=60003561ffff54706005600c60003960056000f360016001556000526000808303602f576011806020036000f090505b60018303604357816011806020036000f590505b8060025560008111156058576001820161ffff555b8060005260206000f3 -242ffaf4896aa1a33fd22f9736aae7f38ec7926a44af5c83ecf4178c5466184b=60043560243560443560643561ffff545b838110156045576460016000f36000526005806020036000f06000811115603a576001820161ffff555b5061ffff5490506010565b5080600052600084036062576020600060206000856103e85a03f4505b60018403607b57602060006020600080866103e85a03f2505b60028403609457602060006020600080866103e85a03f1505b60005180600155600081111560b4576000806000806000856103e85a03f1505b5050505050 -d21bc6ddad58c0de08949ea6b6459b6a157f5d430adc1dcc3dacfc651e30e8c2=7f60016000f300000000000000000000000000000000000000000000000000000060005260006005600080f560005560018055 +52227e17d7647fe54dafe44b4deb62e226a5128df5abeb56b567d38dad4d665a=60003560005260003660006000f5600055 +eab3f419be128f0744b8ff553eac239abd0fa8010eb15c6e908c6906a6bf9206=7f600060005360016000f30000000000000000000000000000000000000000000060005260005b610100811015605157806001536000600a60006000f51515604657600181555b5b6001810190506026565b50600161010055 +99f533052ff998814398779b29eb17d1d9cda70c84a1c5c8de62d89afc739ba9=60003561ffff54706005600c60003960056000f3600160015560005260006000831415603257601160116020036000f090505b600183141560485781601160116020036000f590505b806002556000811115605d576001820161ffff555b8060005260206000f3505050 +aa230d92a57b6ac334b54c9a345753a57bd824c1e86bdae7d5afb69ad0b40db7=60003561ffff54706005600c60003960056000f3600160015560005260006000831415603257601160116020036000f090505b600183141560485781601160116020036000f590505b806002556000811115605d576001820161ffff555b8060005260206000f3505050 +242ffaf4896aa1a33fd22f9736aae7f38ec7926a44af5c83ecf4178c5466184b=60043560243560443560643561ffff545b838110156047576460016000f3600052600560056020036000f06000811115603b576001820161ffff555b505b61ffff5490506010565b508060005260008414156065576020600060206000856103e85a03f4505b600184141560805760206000602060006000866103e85a03f2505b6002841415609b5760206000602060006000866103e85a03f1505b60005180600155600081111560bd5760006000600060006000856103e85a03f1505b5050505050 +d21bc6ddad58c0de08949ea6b6459b6a157f5d430adc1dcc3dacfc651e30e8c2=7f60016000f30000000000000000000000000000000000000000000000000000006000526000600560006000f56000556001600155 0cb7ff2ff5e91cde9ae944d1e97fbd4ba7846b22dd7870a48acde18e2116d79c=626001ff60005260006003601d6000f500 fe0da0e6c1a27cd3fcd9449de9c3fc8ae987439af42de55d589e07dbe20b53a6=6b626001ff6000526003601df36000526000600c60146000f55060006000600060006000735649527a8464a86cae579719d347065f6eb27279620249f0f100 9156fae8844f012720eec7d8aa673ad9cca3ca5dd23b928b9775b0cba8e970d0=626001ff60005260006003601d6001f500 @@ -1433,35 +1433,35 @@ e904075f6bb91684919a73b6f6c2faad062ac28e0d1b4b0324e37dfaed73f2bf=6b626001ff60005 320c0bdac224010fc389c11ded0214972cede15725f62d68bb368ebaa343fe00=6b626001ff6000526003601df36000526000600c60146001f5506000600060006000735649527a8464a86cae579719d347065f6eb27279620249f0fa00 6adc11cbb07e63284761e20c84dd42c2f0357cf416a9765221b113cc8496b91b=6a6130ff6000526002601ef36000526000600b60156000f5506000600060006000736cd0e5133771823da00d4cb545ec8cdab0e38203620249f0fa00 9444e91fe9e94eb25af4daa9780ce737e1a4ffdad450b59d459feb44b5cd1de9=6a6130ff6000526002601ef36000526000600b60156001f5506000600060006000736cd0e5133771823da00d4cb545ec8cdab0e38203620249f0fa00 -340145cf7877773c55440eb898245cda7ff08bffbb771df78ba3304b528ec4c1=600435803b80600080843c600081600080f560008103601a57fe5b505050 -5e89e098fa8a48e4074af88f6823d5ce6305599a4ba824c41d6f249a2a45c363=600160005560018055600060015560016000f3 -c0553b477805522c5df52fb777795c449f563514238aa02af2bff31c12129e9f=60016000556001805560006001556113886000f3 -64f9d48dbb03e233b564cffb000d25d46d619bf7ead017c3a60da12bbda05e92=6001600055600180556000600155fe -4e8170cad07e738c37d8081a5043b7dda9218af13e3e8c2d8cc933f92056030e=60016000556000806000806000620c0dea5af15060016000f3 -aa22e6199d06e6084cda614c3a3db0be54f5f87f362de868f596d2b68148969c=60016000556000806000806000620c0dea5af1506113886000f3 -cc9309c1b6cb2faea24cca4c16c568792e9ba7bd09cef2a913672bd0c38382d6=60016000556000806000806000620c0dea5af150fe -60948fb40224c78fd3a4c9aaa7e7a04973a6f7e7e78805b49dfbf819b847ea08=600160005560018055600080600080620c0dea5af45060016000f3 -a4eafe227ee9964f46af2519ea377ae296a117b84a91a54fde4f4a321d009830=600160005560018055600080600080620c0dea5af4506113886000f3 -3490e27dac61dd1c08c41a6d5fd3d6df2d5c053660def96def65826e1d059792=600160005560018055600080600080620c0dea5af450fe -f82e343e47b2a2164551d322270159a4d6f2e32443eee96e671d40af31792568=6001600055600180556000806000806000620c0dea5af25060016000f3 -6d1cf3d28163e44c11833d12ddb720f6fa12983d9989d57560375cbccc615fcc=6001600055600180556000806000806000620c0dea5af2506113886000f3 -93a4c5e642c58f6ea90ef828723fdacca3b8254909dc7de50b54a035add60ebd=6001600055600180556000806000806000620c0dea5af250fe -13febad19db39c352c37a194221a3658ab3c1d4fc7188ff7e76b4784b62ef8ca=60016000556000806000806000620c0ded5af15060016000f3 -ca690331276298ad3f041bf742be14b44d3b308f90925e5ccc93c5a9b6c0aefd=60016000556000806000806000620c0ded5af1506113886000f3 -bdd7b053de3ae2d9398c43459cb70dd456a242b868144cdf53c4cd94f4b1d471=60016000556000806000806000620c0ded5af150fe -adff105dfff0c5647ec1ce6fc08d2083f927ca29e76e12f9f206a88a49724331=60016000556000806000806000620c0de05af15060016000f3 -68f65e37716676a50230ef8fe1b50f7ae45b9a35c28f893fe6f452ee27c1c85c=60016000556000806000806000620c0de05af1506113886000f3 -6a819c53a9ea47952ca7a953489d5625d102ea77122cf21e7376b6fb99db8872=60016000556000806000806000620c0de05af150fe -36c8e5e4d13fb10e4f3b50768b298da7ed47dd6dc82e68b555184cd0c879345b=6001600055600180556000600155620c0de1803b80600080843c80600080f0506001808201f3 -047d5aaf086bdd6f55cdcc7b5ca8f1de1f7321f7fb8f03ee6dc1b6833d9b00fa=6001600055600180556000600155620c0de1803b80600080843c80600080f05061138860018201f3 -53adb60340f14943f224f428f6d3a8eb7edc14b89fb5b459eba8e1549ea187a1=6001600055600180556000600155620c0de1803b80600080843c80600080f050fe -91bbbde20fcd7e34727b852e501b73199c4273b1b32933dfc335a18e8e8e1f8a=6001600055600180556000600155620c0de1803b80600080843c600081600080f5506001808201f3 -543016ad470d6c160504dc6c9c8ddf08b16707bde3f564c397c001a8ddeba5b6=6001600055600180556000600155620c0de1803b80600080843c600081600080f55061138860018201f3 -47916ef90b042f3a5106cff87fc7a949b0f1d40e763cfcd201ec85b4bfde6ec8=6001600055600180556000600155620c0de1803b80600080843c600081600080f550fe +340145cf7877773c55440eb898245cda7ff08bffbb771df78ba3304b528ec4c1=600435803b8060006000843c60008160006000f56000811415601d57fe5b505050 +5e89e098fa8a48e4074af88f6823d5ce6305599a4ba824c41d6f249a2a45c363=60016000556001600155600060015560016000f3 +c0553b477805522c5df52fb777795c449f563514238aa02af2bff31c12129e9f=6001600055600160015560006001556113886000f3 +64f9d48dbb03e233b564cffb000d25d46d619bf7ead017c3a60da12bbda05e92=600160005560016001556000600155fe +4e8170cad07e738c37d8081a5043b7dda9218af13e3e8c2d8cc933f92056030e=600160005560006000600060006000620c0dea5af15060016000f3 +aa22e6199d06e6084cda614c3a3db0be54f5f87f362de868f596d2b68148969c=600160005560006000600060006000620c0dea5af1506113886000f3 +cc9309c1b6cb2faea24cca4c16c568792e9ba7bd09cef2a913672bd0c38382d6=600160005560006000600060006000620c0dea5af150fe +60948fb40224c78fd3a4c9aaa7e7a04973a6f7e7e78805b49dfbf819b847ea08=600160005560016001556000600060006000620c0dea5af45060016000f3 +a4eafe227ee9964f46af2519ea377ae296a117b84a91a54fde4f4a321d009830=600160005560016001556000600060006000620c0dea5af4506113886000f3 +3490e27dac61dd1c08c41a6d5fd3d6df2d5c053660def96def65826e1d059792=600160005560016001556000600060006000620c0dea5af450fe +f82e343e47b2a2164551d322270159a4d6f2e32443eee96e671d40af31792568=6001600055600160015560006000600060006000620c0dea5af25060016000f3 +6d1cf3d28163e44c11833d12ddb720f6fa12983d9989d57560375cbccc615fcc=6001600055600160015560006000600060006000620c0dea5af2506113886000f3 +93a4c5e642c58f6ea90ef828723fdacca3b8254909dc7de50b54a035add60ebd=6001600055600160015560006000600060006000620c0dea5af250fe +13febad19db39c352c37a194221a3658ab3c1d4fc7188ff7e76b4784b62ef8ca=600160005560006000600060006000620c0ded5af15060016000f3 +ca690331276298ad3f041bf742be14b44d3b308f90925e5ccc93c5a9b6c0aefd=600160005560006000600060006000620c0ded5af1506113886000f3 +bdd7b053de3ae2d9398c43459cb70dd456a242b868144cdf53c4cd94f4b1d471=600160005560006000600060006000620c0ded5af150fe +adff105dfff0c5647ec1ce6fc08d2083f927ca29e76e12f9f206a88a49724331=600160005560006000600060006000620c0de05af15060016000f3 +68f65e37716676a50230ef8fe1b50f7ae45b9a35c28f893fe6f452ee27c1c85c=600160005560006000600060006000620c0de05af1506113886000f3 +6a819c53a9ea47952ca7a953489d5625d102ea77122cf21e7376b6fb99db8872=600160005560006000600060006000620c0de05af150fe +36c8e5e4d13fb10e4f3b50768b298da7ed47dd6dc82e68b555184cd0c879345b=600160005560016001556000600155620c0de1803b8060006000843c8060006000f050600160018201f35050 +047d5aaf086bdd6f55cdcc7b5ca8f1de1f7321f7fb8f03ee6dc1b6833d9b00fa=600160005560016001556000600155620c0de1803b8060006000843c8060006000f05061138860018201f35050 +53adb60340f14943f224f428f6d3a8eb7edc14b89fb5b459eba8e1549ea187a1=600160005560016001556000600155620c0de1803b8060006000843c8060006000f050fe5050 +91bbbde20fcd7e34727b852e501b73199c4273b1b32933dfc335a18e8e8e1f8a=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f550600160018201f35050 +543016ad470d6c160504dc6c9c8ddf08b16707bde3f564c397c001a8ddeba5b6=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f55061138860018201f35050 +47916ef90b042f3a5106cff87fc7a949b0f1d40e763cfcd201ec85b4bfde6ec8=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f550fe5050 8648b214afb7430e364eba9298aef2f4cf789dfe3c10b7169d60aca559d4db65=6000600155 80ab328c7bf9ff6ec231b37fd3a29be9a4a52ce75a9403ac1f1d3dfa4c12e8b6=32ff d788f00379736afa7b39a7532465cb8ea82a12dd35d61daec41b81356fda4cc2=60ff60005260206000a060fa60206000a160fb60fa60206000a260fc60fb60fa60206000a360fd60fc60fb60fa60206000a4 -23a0e63111b844c94ad18cf0e41bce1a67fa8635ec21efaf18bc6014c29f084a=60016000556000805560016000f3 +23a0e63111b844c94ad18cf0e41bce1a67fa8635ec21efaf18bc6014c29f084a=6001600055600060005560016000f3 a2a11955877ae151e36f329f8bc45ab5a5565ee1d755940576841438208b830d=6d6460016001556000526005601bf36000526000600e60126000f500 7761f9e47080a9dea07ad74dcd0b4eee6bb2bc0a5d2cbe5d284f858b031765de=6d6460016001556000526005601bf36000526000600e60126000f5503d6001556000600060003e60005160025500 5dd098f4422594a7933ff26fb535c61299b4658a6cf97ac8177285a779953a47=6020600060006000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b5af2506020600060003e60005160015500 @@ -1475,15 +1475,15 @@ ea87b03a322010861c9c3f2d91113817ed5af1ad5509d1d296e953d885d261f6=600035600052600 9b80084d8b54d392190ba850971ca31ab58a26470e85844e00a53d6647973a45=6000356000526000516002016000526104006000511460435760006000602060006104006000511473c94f5374fce5edbc8e2a8697c15331677e6ebf0b5af150606d565b78686000600060006000f56000526000600960176000f56001556020526000601960276000f56001555b00 3507842b88aa1c0e1f22cf1cbc3dd8f2a37e4dfd544cc4711468651f49f7110b=7d606460006000396103e85a10601b576000606460006000f5601d565b5a5b6000526000601e60026000f500 a24c75b3028d6c82ba28bd9349aa3a6c94109a221c8cf79637c1873255454624=69600c600055600d6001556000526000600a60166000f500 -88ab1b584b23704782ea1a04695ae304adf2f3826b4297db965d2568d2a1e1d8=60086002556000600060006000f550600c60035500 9906997c04cc7ac0c88e7e25b9cf3b0b36b808b8090b395adb1fb1ea00d94870=60016000556000600060006000600073b000000000000000000000000000000000000000600035f1600155600c60045500 +88ab1b584b23704782ea1a04695ae304adf2f3826b4297db965d2568d2a1e1d8=60086002556000600060006000f550600c60035500 b9134334f82ce111680bb32468b9df3d41061303d1511e4b9361eb7d22dbbd74=30506000600e80602860003960006000f56002553d6000556020600060003e6000516001550000fe6211223360005260206000fd0000 01775ea3ee583a2e77f1f14633400a5385e341e5ae3ac38eec026cd58fcb252e=6e600160005560016000fd60116001556000526000600f60116001f5600155600c60005500 3d57290be527913c1e95ad5333a6100955c93d8856983312dc60e9e56ab52715=6000600e80601760003960006000f5503d6000550000fe6211223360005260206000fd0000 b37864a984e35fc2d0e7ceb61198503de2988d27a5510464f54dbaba442ffd48=7d111122223333444455556666777788889999aaaabbbbccccddddeeeeffff60005260206000f300 73d60d979b543a41feef88f3749f87baac94113d0540f97fe77a301649960067=60206000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f1506000600e80603e60003960006000f5503d6000550000fe6211223360005260206000f30000 -8a168d3c2b531bbfb7eed870f0c15ff2d5229fe26db10fe47625a97cbcb51e88=60006000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f1506000600e80603e60003960006000f5503d6000550000fe6211223360005260206000f30000 6c6d1b053e052e2aaaa460b4c0db743515eb307279b458b6a2ef9b18c846db38=7d111122223333444455556666777788889999aaaabbbbccccddddeeeeffff60005260206000f30000 +8a168d3c2b531bbfb7eed870f0c15ff2d5229fe26db10fe47625a97cbcb51e88=60006000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f1506000600e80603e60003960006000f5503d6000550000fe6211223360005260206000f30000 c79e0198cf5bd2391dfab79ab4a5f727191b360097e4480f46ba6b55343c6fd1=60006000536000600160006000f560005500 a1c0af891959756f7603db930bde8c199d25c3b45e93892f65e2fc58a6e84d01=60566000536000600160006000f560005500 170d0e39252912ff91a1ecaca213518f87e5ab208f0b1de87b643d79b6e5a7dc=60016000536000600160006000f560005500 @@ -1493,19 +1493,19 @@ af92af26df14fab9cfeacf2d1ea273af589f14a70a6a9f85c81fb3b8a1a9634e=626001ff6000526 1f224ef3dee7bce1e818896ba56cea12fa5929f5322ff3cc30935666a995a355=626001ff60005260006003601d6001f560005500 343399ee1d228e1f9967c71d5018fcb3a10487d7158a3686918df63869426864=60006003601d6000f560005500 4dea22089412be26f403665dec5b440f064752f4e3f1580981b6f743f6914f10=6160a960005260006002601e6001f560005500 -20aed0d47cdf2f12c13f245182de6e26d4c3e26ebc16b02e6e09da2268d389e3=7c600060015414601157600a6000f3601c565b6001600155600a6000f35b6000526000601d60036001f56001556000601b60056001f560025500 ca6d627872c35c5437a29a3fabda1f3f19b675a53ff0c281339bb7c0c8d6409c=7a600060015414601157600a6000f3601a565b60016001556001ff5b6000526000601b60056001f56001556000601b60056001f560025500 8d71f1baf932ccfe51802cd53663486a5e45cb95151cb1a322ec39a141518cd3=600060006000600060006000355af100 +20aed0d47cdf2f12c13f245182de6e26d4c3e26ebc16b02e6e09da2268d389e3=7c600060015414601157600a6000f3601c565b6001600155600a6000f35b6000526000601d60036001f56001556000601b60056001f560025500 0ceab5d26ca0b097ec0e2b5a810d9a46a576747f5a2ee39acf1125dbefa1e379=6000602980601160003960006000f500fe61010060006000600073f2000000000000000000000000000000000000005afa50600051600a550000 -7b3b54ebb35862901dec1f208e1a51ae747dabaf9434b1c8a5272baa7eaa7207=6000600060006000600073f0000000000000000000000000000000000000005af100 -a27ff87311b40a91645d0e29e85f17bef428ee98334082d8810a81ebc72bfe80=6000602380601360003960006000f5500000fe30600055303160015532600255336003553460045536600555386006553a6007550000 02aa5a85c50eccbdd3714fe0c173fe47a7ec78e3b98e0166542c0d3d55dc1bf2=6000602480601360003960006000f5500000fe6000600060006000600073f0000000000000000000000000000000000000005af2500000 +556f9c674339d5fd4c44ca3c79b25d43b95ba0dfc0753b4e551406a92576edb9=6000602280601360003960006000f5500000fe600060006000600073f0000000000000000000000000000000000000005af4500000 +a27ff87311b40a91645d0e29e85f17bef428ee98334082d8810a81ebc72bfe80=6000602380601360003960006000f5500000fe30600055303160015532600255336003553460045536600555386006553a6007550000 c3fa0ace59c7d664250610583f9f21f2688f488bd99e107964cf0b1d69977d17=600060006000600073f0000000000000000000000000000000000000005af4500000 fb57d4384857666596aa0f1ae985061514c50d24c6536985e93c7721f26ab366=6000600060006000600073f0000000000000000000000000000000000000005af200 -a36567eb706d26cb1f601f73396df65f77eec2935c59d347a1f1525b4e7e5dbc=61010060006000600073f2000000000000000000000000000000000000005afa50600051600a5500 f2cba7b387262c5d65c0c23f4c7920ed5cb1ce9a55eb6959781cf1f39775f143=6000602980601160003960006000f500fe3060005230316020523260405233606052346080523660a0523860c0523a60e0526101006000f30000 -556f9c674339d5fd4c44ca3c79b25d43b95ba0dfc0753b4e551406a92576edb9=6000602280601360003960006000f5500000fe600060006000600073f0000000000000000000000000000000000000005af4500000 +a36567eb706d26cb1f601f73396df65f77eec2935c59d347a1f1525b4e7e5dbc=61010060006000600073f2000000000000000000000000000000000000005afa50600051600a5500 c3ce08944bad51dc73b907a561f88e768067ad7797c597f4e57126175c6be569=6000602480601360003960006000f5500000fe6000600060006000600073f0000000000000000000000000000000000000005af1500000 +7b3b54ebb35862901dec1f208e1a51ae747dabaf9434b1c8a5272baa7eaa7207=6000600060006000600073f0000000000000000000000000000000000000005af100 fd39994f2b05bfbff9216d2e0ff446e83c2504d25ac18ca1c69efbf13d5ce691=6000600060006000f500 8709980edfa2db2bca11f56a4f8ccf4f40130495b192afc3d66338be29c79fe8=64600160015560005260006005601b6000f500 edc3d79069c655807240f56f6d25b23bc70fb7f74b6c3c72ceb022842193cf96=6000600060006001f500 @@ -1536,7 +1536,7 @@ fbb431f2189ebaffc4f9c1b0a170a321958396ed8b683e1ba534787f4064beba=600060298060206 3694d6a2e270143e1b7ad42de73c57175a13c50dfd52d1be17f5b34ba872fd34=6000600d80601760003960006000f5503d6000550000fe6211223360005260206000f300 4cc61e1ed6d2e4e5227c4388744a5b9cdacad746f9620ddb6ce11a9aabd8c23b=600c60015500 63d1873266f31c5c1211c5e798508c6222574120b233cfc18cf34ca6ac238bfc=5a600055602060006000f06001555a6002556000600060006000600073e1ecf98489fa9ed60a664fc4998db699cfa39d4061ea60f16003555a60645500 -50ac9394e4391fc0702cfc7b594d452128fbda9f4060d0f949916d03701fcc4d=60003560005236600080f0600055 +50ac9394e4391fc0702cfc7b594d452128fbda9f4060d0f949916d03701fcc4d=6000356000523660006000f0600055 6e7614d58424c8409591332959588c34ee21514f7a8ea69e76a59e4c994c50cc=5a600055602060006000f06001555a6002556000600060006000600060015461ea60f16003555a60645500 c014473615e7e31367489957d58724908eeb02d7bc2200959781a5bbfaa5381e=5a600055602060006000f06001555a6002556000600060006000600160015461ea60f16003555a60645500 bc1e9da083d9ee4773f2e596ffe3d2f8d56fc65822fb05e489dab7f3d9e1d9f0=5a600055602060006000f06001555a60645500 @@ -1544,76 +1544,76 @@ bc1e9da083d9ee4773f2e596ffe3d2f8d56fc65822fb05e489dab7f3d9e1d9f0=5a6000556020600 588b8618ca23c9938da936cad23b8a754426f9101d2cd743bb76d08fb6d54491=5a6000557f600c6000556000600060006000600073c94f5374fce5edbc8e2a8697c15331676000527f7e6ebf0b61ea60f1000000000000000000000000000000000000000000000000602052604060006000f06001555a6002556000600060006000600060015461ea60f16003555a60645500 9f443d4664f4165129254b21d2aa9f402e990ec3f21c8a3557c9053f13a8bb47=5a6000557f600c6000556000600060006000600073c94f5374fce5edbc8e2a8697c15331676000527f7e6ebf0b61ea60f1000000000000000000000000000000000000000000000000602052604060006000f06001555a6002556000600060006000600160015461ea60f16003555a60645500 4fef7f1b0a5d0be8d7231aba1a5e3ea4d34f7dc7dd96071b4c04e6e43716bd91=5a6000557f600c6000556000600060006000600073c94f5374fce5edbc8e2a8697c15331676000527f7e6ebf0b61ea60f1000000000000000000000000000000000000000000000000602052604060006000f06001555a60645500 -0e64b07c5f8a4b1d805d72a663b7922bebd1fffc63fdda9f74ee833a962cd08f=7f600060005360016000f30000000000000000000000000000000000000000000060005260005b610100811015604b5780600153600a600080f0604157600181555b6001810190506026565b50600161010055 -0f80ade5cd0aebbf46caac3e6642ca49675bc577b59305821c4f28ff215d106e=7f60016000f30000000000000000000000000000000000000000000000000000006000526005600080f060005560018055 +0e64b07c5f8a4b1d805d72a663b7922bebd1fffc63fdda9f74ee833a962cd08f=7f600060005360016000f30000000000000000000000000000000000000000000060005260005b610100811015604f5780600153600a60006000f01515604457600181555b5b6001810190506026565b50600161010055 +0f80ade5cd0aebbf46caac3e6642ca49675bc577b59305821c4f28ff215d106e=7f60016000f3000000000000000000000000000000000000000000000000000000600052600560006000f06000556001600155 8f2b325bc960e0b2589c62f03544cb60df9ff0743d658cd3b2531de5b60d4036=6000356000545560016000540160005500 2ab24936454b2c8365281adf6aa1abbeab4c3834a3470510287a934d1f9fd054=60068061004c610100396102005260db8061005260003961022052600160043514603757615a17610200516101000160006000f56045565b610200516101000160006000f05b6102405200fe60ff60005500610100610100610100395861026052600060006020610260600061da7a62fffffff1503061026052600060006020610260600061da7a62fffffff1503861026052600060006020610260600061da7a62fffffff150303b61026052600060006020610260600061da7a62fffffff15060206000610100396101005161026052600060006020610260600061da7a62fffffff15060206000610100303c6101005161026052600060006020610260600061da7a62fffffff1505861026052600060006020610260600061da7a62fffffff1506101003803610100f300 8fe0d0b35be498ea58c02e2f3bfd06f7ff8c08eb81f04115affacd68520f5ee1=601d60005500 6bc0f214f1d46352212bff0bb2bf8f22e56a258863ee84aab805ba06e3044fde=60f860020a6000350461010052601580610158610300396105405260068061016d61020039610520526001610100511461004957615a17610540516103006000f561060052610058565b610540516103006000f0610600525b586020553d6010556106005160115560006000600060006000738af6a7af30d840ba137e8f3f34d54cfb8beba6e261fffff16106405258602155600161064051036012553d601355600060006000600060007340f1299359ea754ac29eb2662a1900752bf8275f61fffff16106405258602255600161064051036014553d601555738af6a7af30d840ba137e8f3f34d54cfb8beba6e23b6030556030546000610660738af6a7af30d840ba137e8f3f34d54cfb8beba6e23c610660516031557340f1299359ea754ac29eb2662a1900752bf8275f3b60325560325460006106607340f1299359ea754ac29eb2662a1900752bf8275f3c6106605160335500fe600680600f61020039610200f300fe60ff6000550060ff60005500 -3b0b68a7a28df4b5781690a493c35a0625901aa7b3dcb525b1949e33e7bdc4b4=6000600060006000600060003562013880f100 6ec4750d6b26b36a640db94d86ffea865b5e7c2c4ec374fe9bfcabc0ba2847b5=6460016001556000526005601b6000f060015500 -faa74b0b8c25e339bcbc2891614c363020f5bcabc51694e5519efe90cc6184d3=600435803b80600080843c80600080f060008103601857fe5b505050 -a27d87251798a593b75d6fc3305ed0eba86be2c4281283e6ec41a596d6ea23ed=600160005560018055600060015560016000f3 -cc0f8546303c24ff600f1084b88781cc91f432173256a6e0fec568f530130ca6=60016000556001805560006001556113886000f3 -af7b42087df475463f3f4681f43871f54737ecb874aeccc22c513978312d5c7a=6001600055600180556000600155fe -a80a8bffdd8dfcedecf9fec790b91200681b9680e658f239cf2f43ce41872497=60016000556000806000806000620c0dea5af15060016000f3 -1b3e88ede6b23b56ae8e682a5f59f5b7952cd6d0a4021feb90ba28d9c33881bf=60016000556000806000806000620c0dea5af1506113886000f3 -5e64f31cc3d60a722b54b1dd990213d114b43afb91bbdf1fbd253a0b0e09da2e=60016000556000806000806000620c0dea5af150fe -9756ccce0af3ab7f2ddcd9ead3417771c3e13e76f1982ef66757f2b9773908a7=600160005560018055600080600080620c0dea5af45060016000f3 -9859a54aafd2db530ca791b7cc9f75dc42a4750f17a2572175e5ff253401dc5c=600160005560018055600080600080620c0dea5af4506113886000f3 -6cf00b462393771a4d13d9a6a81721d3f576cfcf6d980a7ac0bf5ce9feb3c90e=600160005560018055600080600080620c0dea5af450fe -4f1407a0d00cfdd4938f41333df0db261155dcb8957dbf6e8a5aea79b4c39d64=6001600055600180556000806000806000620c0dea5af25060016000f3 -de71dee39e096d303abbe8e0d9b854de76c7abba0f5c868b618ea8f18e7adaa9=6001600055600180556000806000806000620c0dea5af2506113886000f3 -6b70aedf8a9e0995baf0ca14afadf1f1b2b8ff97b07ddc35c1654a17b3321c51=6001600055600180556000806000806000620c0dea5af250fe -53964f63ba7984d3ea9f17e77bf61770d262605e1b9afc6b5dc3b08ce76c9e07=60016000556000806000806000620c0ded5af15060016000f3 -2823105003d7f7bcb6a57448f36820843bdba58e19b23e548b99f0804b93fdb2=60016000556000806000806000620c0ded5af1506113886000f3 -16a843c37a1f02710eb64f1b0a8c09151cf80cc38bebae862f782b7d5c16c92f=60016000556000806000806000620c0ded5af150fe -62e06c8f58c452573ea2dedf8f1775060d6ceca56f811765344a61868cb5c5b6=60016000556000806000806000620c0de05af15060016000f3 -a30a1c1183bf98b15857ad1054e59dd365ecad93d3a22ec182750e2879cc0ad3=60016000556000806000806000620c0de05af1506113886000f3 -d5995b05f6a20e0100d0cfd60f01e0ad1094b297fa5311107fca3c5e96108b2e=60016000556000806000806000620c0de05af150fe -8cfc1ffde61af5b3a4c41ca48021e77291241e208e853eab1d5dce96c392b1d6=6001600055600180556000600155620c0de1803b80600080843c80600080f0506001808201f3 -0793730d42a2860ea9ee769705c5870d6cda60dfb4d781105c7f45db491026ea=6001600055600180556000600155620c0de1803b80600080843c80600080f05061138860018201f3 -9fc54038403be74936d2bf3282e4986caa6e7867abf72b992b78dac6b9ed7555=6001600055600180556000600155620c0de1803b80600080843c80600080f050fe -fa33b07cd047c51c449ba132a5bff6ba06f377530b02d88e2befe8a6663b67c4=6001600055600180556000600155620c0de1803b80600080843c600081600080f5506001808201f3 -44fcf2437a6eb80065abd34775b314990164b8cbd17c325aeac7932035089682=6001600055600180556000600155620c0de1803b80600080843c600081600080f55061138860018201f3 -b253d47579a0e1c65178b50c589e110c1efe4d2b82771cdfb1b85820bc56d951=6001600055600180556000600155620c0de1803b80600080843c600081600080f550fe +3b0b68a7a28df4b5781690a493c35a0625901aa7b3dcb525b1949e33e7bdc4b4=6000600060006000600060003562013880f100 +faa74b0b8c25e339bcbc2891614c363020f5bcabc51694e5519efe90cc6184d3=600435803b8060006000843c8060006000f06000811415601b57fe5b505050 +a27d87251798a593b75d6fc3305ed0eba86be2c4281283e6ec41a596d6ea23ed=60016000556001600155600060015560016000f3 +cc0f8546303c24ff600f1084b88781cc91f432173256a6e0fec568f530130ca6=6001600055600160015560006001556113886000f3 +af7b42087df475463f3f4681f43871f54737ecb874aeccc22c513978312d5c7a=600160005560016001556000600155fe +a80a8bffdd8dfcedecf9fec790b91200681b9680e658f239cf2f43ce41872497=600160005560006000600060006000620c0dea5af15060016000f3 +1b3e88ede6b23b56ae8e682a5f59f5b7952cd6d0a4021feb90ba28d9c33881bf=600160005560006000600060006000620c0dea5af1506113886000f3 +5e64f31cc3d60a722b54b1dd990213d114b43afb91bbdf1fbd253a0b0e09da2e=600160005560006000600060006000620c0dea5af150fe +9756ccce0af3ab7f2ddcd9ead3417771c3e13e76f1982ef66757f2b9773908a7=600160005560016001556000600060006000620c0dea5af45060016000f3 +9859a54aafd2db530ca791b7cc9f75dc42a4750f17a2572175e5ff253401dc5c=600160005560016001556000600060006000620c0dea5af4506113886000f3 +6cf00b462393771a4d13d9a6a81721d3f576cfcf6d980a7ac0bf5ce9feb3c90e=600160005560016001556000600060006000620c0dea5af450fe +4f1407a0d00cfdd4938f41333df0db261155dcb8957dbf6e8a5aea79b4c39d64=6001600055600160015560006000600060006000620c0dea5af25060016000f3 +de71dee39e096d303abbe8e0d9b854de76c7abba0f5c868b618ea8f18e7adaa9=6001600055600160015560006000600060006000620c0dea5af2506113886000f3 +6b70aedf8a9e0995baf0ca14afadf1f1b2b8ff97b07ddc35c1654a17b3321c51=6001600055600160015560006000600060006000620c0dea5af250fe +53964f63ba7984d3ea9f17e77bf61770d262605e1b9afc6b5dc3b08ce76c9e07=600160005560006000600060006000620c0ded5af15060016000f3 +2823105003d7f7bcb6a57448f36820843bdba58e19b23e548b99f0804b93fdb2=600160005560006000600060006000620c0ded5af1506113886000f3 +16a843c37a1f02710eb64f1b0a8c09151cf80cc38bebae862f782b7d5c16c92f=600160005560006000600060006000620c0ded5af150fe +62e06c8f58c452573ea2dedf8f1775060d6ceca56f811765344a61868cb5c5b6=600160005560006000600060006000620c0de05af15060016000f3 +a30a1c1183bf98b15857ad1054e59dd365ecad93d3a22ec182750e2879cc0ad3=600160005560006000600060006000620c0de05af1506113886000f3 +d5995b05f6a20e0100d0cfd60f01e0ad1094b297fa5311107fca3c5e96108b2e=600160005560006000600060006000620c0de05af150fe +8cfc1ffde61af5b3a4c41ca48021e77291241e208e853eab1d5dce96c392b1d6=600160005560016001556000600155620c0de1803b8060006000843c8060006000f050600160018201f35050 +0793730d42a2860ea9ee769705c5870d6cda60dfb4d781105c7f45db491026ea=600160005560016001556000600155620c0de1803b8060006000843c8060006000f05061138860018201f35050 +9fc54038403be74936d2bf3282e4986caa6e7867abf72b992b78dac6b9ed7555=600160005560016001556000600155620c0de1803b8060006000843c8060006000f050fe5050 +fa33b07cd047c51c449ba132a5bff6ba06f377530b02d88e2befe8a6663b67c4=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f550600160018201f35050 +44fcf2437a6eb80065abd34775b314990164b8cbd17c325aeac7932035089682=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f55061138860018201f35050 +b253d47579a0e1c65178b50c589e110c1efe4d2b82771cdfb1b85820bc56d951=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f550fe5050 72a954af5006562f0dfb34e46464fdcd1a793f13b7356b2b6917ce16ae9fe447=6d6460016001556000526005601bf3600052600e60126000f000 8d3966a550258f89fd720a3a7b1a679fdd35354a926a6b798f38074a44c1352b=6d6460016001556000526005601bf3600052600e60126000f0503d6001556000600060003e60005160025500 cace50ebb0fb04dc5d78ecaf4ed9bdad4c5ba918c13b44605d82630d472cfaf5=6d6460016001556000526005601bf3600052600e60126000f0503d6001556020600060003e60005160025500 202db2b317af70e9ac3cda5a8d314345fe4b2188daea61087e9908fe7d45bcaa=726960016001556001600255600052600a6016f36000526013600d6000f0503d60020a00 -c66ba2e979c0d75239d1097adb2387c7918cf6ba151ad35697e0e17ad05f674b=6d6460016001556000526005601bf3600052600e60126000f05060206000fd00 4f8c74954df3634bebd2fc766b4288f4ddbf31a4780966679927bbbc5c211772=6020600060006000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6159d8f15060005160015500 -1a282d2e56e29c13ec3fb7abb753de1f5d5b0d384059764043de57d1bb1bf213=6d6460016001556000526005601bf3600052600e60126000f0506000600060006000600073094f5374fce5edbc8e2a8697c15331677e6ebf0b612710f25060206000fd00 +c66ba2e979c0d75239d1097adb2387c7918cf6ba151ad35697e0e17ad05f674b=6d6460016001556000526005601bf3600052600e60126000f05060206000fd00 f7294423dfa4154ea5a6b3ac3cc4d02bb309bef32739d78422b4ac88dc4d838e=622fffff60002000 +1a282d2e56e29c13ec3fb7abb753de1f5d5b0d384059764043de57d1bb1bf213=6d6460016001556000526005601bf3600052600e60126000f0506000600060006000600073094f5374fce5edbc8e2a8697c15331677e6ebf0b612710f25060206000fd00 996cb8a428e971c6f11083e3145eec7d57824c1e0a3c7ab0b2c813797bf6dc85=386000556000361115600f576000ff5b -0ab50e48e5899bad047f2e35a53e0bdfa7f586424a34e03c540244e910bf42c4=620c0de0803b600080833c6160006000f3 -368981308235cb257758010274fb07e7d9f8eed95cc019c6533d9cb6e944b77b=60018055600035602035620c0de1803b80600080843c60005b8481101560375781600080f08060208302840152506001810190506018565b506000831115604257fe5b6020840281f3 -f56e738504b614f030b881a1aa1ab1fe0f8bf17565fd539ce0b000df49765dbc=600435602435604435606435836000526000602052604060208502808260406000620c0deb60025a04f460008103603557600080fd5b856000528460205260208702604001925060208602915081836040600080620c0deb60025a04f190506000810360725760008503607157600080fd5b5b866000860360805786880190505b60005b8181101560ad5760208102604001516000806000806000856103e85a03f150506001810190506083565b5060005b8581101560db5760208102604001516000806001600080856103e85a03f1505060018101905060b1565b505050505050505050 +0ab50e48e5899bad047f2e35a53e0bdfa7f586424a34e03c540244e910bf42c4=620c0de0803b60006000833c6160006000f350 +368981308235cb257758010274fb07e7d9f8eed95cc019c6533d9cb6e944b77b=6001600155600035602035620c0de1803b8060006000843c60005b84811015603b578160006000f08060208302840152505b600181019050601a565b506000831115604657fe5b6020840281f350505050 +f56e738504b614f030b881a1aa1ab1fe0f8bf17565fd539ce0b000df49765dbc=600435602435604435606435836000526000602052604060208502808260406000620c0deb60025a04f4600081141560375760006000fd5b85600052846020526020870260400192506020860291508183604060006000620c0deb60025a04f190506000811415607857600085141560775760006000fd5b5b86600086141560875786880190505b60005b8181101560b757602081026040015160006000600060006000856103e85a03f150505b600181019050608a565b5060005b8581101560e857602081026040015160006000600160006000856103e85a03f150505b60018101905060bb565b505050505050505050 b6c5a45d051cd5bc14c41fa06350d5c433107570d31b02b189232f4d40f29831=60043561010052602435610120526044356101405260046101405114600061014051141761002f5760005061003e565b60218061025061030039610540525b6001610140511461005157600050610060565b60298061027161030039610540525b6002610140511461007357600050610082565b60268061029a61030039610540525b60036101405114610095576000506100a4565b602c806102c061030039610540525b600561014051146100b7576000506100c6565b6028806102ec61030039610540525b600661014051146100d9576000506100e8565b602a8061031461030039610540525b60128061033e61020039610520526001610100511461011757615a17610540516103006000f561060052610126565b610540516103006000f0610600525b586020553d601055600461014051143d1761014357600050610153565b602060006101603e610160516011555b610600513b61056052610560516000610400610600513c61056051610520510360125561040051610200510360135560016101205114610195576000506101ac565b600060006000600060006106005161fffff1610640525b600261012051146101bf576000506101d6565b600060006000600060006106005161fffff2610640525b600361012051146101e9576000506101fe565b60006000600060006106005161fffff4610640525b6004610120511461021157600050610226565b60006000600060006106005161fffffa610640525b58602155600061012051141561023e5760005061024d565b600161064051036014553d6015555b00fe601280600f61020039610200f300fe600060006000600060006160a761fffff100622fffff60002050601280601761020039610200f300fe600060006000600060006160a761fffff10060006000fd601280601461020039610200f300fe600060006000600060006160a761fffff1006160a760005260206000fd601280601a61020039610200f300fe600060006000600060006160a761fffff1006160a760005200601280601661020039610200f300fe600060006000600060006160a761fffff1006160a76000526000ff601280601861020039610200f300fe600060006000600060006160a761fffff100600060006000600060006160a761fffff100 e6c9a9cd0576a0827c6d7e153bad1773be79b062b739d821e314d228becc90d3=6160a760005500 1269e1165214001763734f4ab9e8b4af94c6784128543571388100b0a8c2dd53=63deadbeef6000526160a760205260406000f3 7b5d67ae9317ae71fd4c0d26534e80a90ecc51e6970da1b80ff0de5896ae993a=650bad0bad0bad60005260206000fd cd4d3c09da11087ab7bf7869059e607ed149955ae16144b9b704b83d17b6552f=61600d60005260206000f3 -936fa4ee803af69ccca98fa58ec947c8200668c125be49d4673bd30b100c9f39=6040610100600080600061da7a5af16010553d6011556101005160125561012051601355600035803b80600080843c80600080f06000553d6001553d60006102003e61020051600255610220516003555050 -5365da138b0f9466cea68b6eecf601e402750cb8e13782201eaa011bd716f3d5=6040610100600080600061da7a5af16010553d6011556101005160125561012051601355600035803b80600080843c615a1781600080f56000553d6001553d60006102003e61020051600255610220516003555050 -2919a2ea3a06a002625142a11b44d8ee0180ba391c0273c49ee6e66b584127ce=6040610100600080600061da7a5af16010553d6011556101005160125561012051601355600035803b80600080843c63bad05a1781600080f56000553d6001553d60006102003e61020051600255610220516003555050 -16977ca088151212b46237b6c336d138f8bfd24129a63424ce9aec7eab7d47ad=6040610100600080600061da7a5af16010553d6011556101005160125561012051601355600035803b80600080843c80600080f06000553d6001553d60006102003e61020051600255610220516003555050 -7945813967cb96252b4d804e32df042ffd0df0cdbde6294bbdf40b02ed0f0262=6004356024358162c0de00016040610100600080600061da7a5af16010553d60115561010051601255610120516013555a600683036044576004615654026175300190505b82600052602061020060206000808686f1806000553d600155610200516002555050505050 -0f40edb53bcfa6f1d0b2756709e14a6609b10de043a398af6291a6beda197a48=60001960005260206101008039610100516000f3 -614f9f94e270fc2022d8845ecd77cc8daabca21b4b140b8f9f7c4c61753cae23=60043560243560443561c0de3b8060008061c0de3c826001820353816101005260008460f0811460345760f58114604157604e565b610120600080f09150604e565b615a17610120600080f591505b50806000555a600155803f6002555050505050 +936fa4ee803af69ccca98fa58ec947c8200668c125be49d4673bd30b100c9f39=604061010060006000600061da7a5af16010553d6011556101005160125561012051601355600035803b8060006000843c8060006000f06000553d6001553d60006102003e61020051600255610220516003555050 +5365da138b0f9466cea68b6eecf601e402750cb8e13782201eaa011bd716f3d5=604061010060006000600061da7a5af16010553d6011556101005160125561012051601355600035803b8060006000843c615a178160006000f56000553d6001553d60006102003e61020051600255610220516003555050 +2919a2ea3a06a002625142a11b44d8ee0180ba391c0273c49ee6e66b584127ce=604061010060006000600061da7a5af16010553d6011556101005160125561012051601355600035803b8060006000843c63bad05a178160006000f56000553d6001553d60006102003e61020051600255610220516003555050 +16977ca088151212b46237b6c336d138f8bfd24129a63424ce9aec7eab7d47ad=604061010060006000600061da7a5af16010553d6011556101005160125561012051601355600035803b8060006000843c8060006000f06000553d6001553d60006102003e61020051600255610220516003555050 +7945813967cb96252b4d804e32df042ffd0df0cdbde6294bbdf40b02ed0f0262=6004356024358162c0de0001604061010060006000600061da7a5af16010553d60115561010051601255610120516013555a60068314156046576004615654026175300190505b8260005260206102006020600060008686f1806000553d600155610200516002555050505050 +0f40edb53bcfa6f1d0b2756709e14a6609b10de043a398af6291a6beda197a48=600019600052602061010061010039610100516000f3 +614f9f94e270fc2022d8845ecd77cc8daabca21b4b140b8f9f7c4c61753cae23=60043560243560443561c0de3b806000600061c0de3c826001820353816101005260008460f0811460355760f581146043576051565b61012060006000f091506051565b615a1761012060006000f591505b50806000555a600155803f6002555050505050 5a7d04b359943ed94efac3837ef063438beffff6facc990229c19b49b7348e1b=600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff460015500 ae55b10532d3bf62548b4bff144544b45ee68ff8efeb6ef266609904dbe7a9b3=600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b610401600054046001036127105a0302f46001556103e86000540260010160025500 b424a9fc173523f0ddaf08491e9a131e4cf6320fa57fd3687e17db02d8391a36=6000600060006000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffff16002556000600060006000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffff1600355600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff460015500 512a7e819ae177c42e94558e8dbfdd801a2dc4706b3148d3b5b9350071a4f85e=600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b620186a060005402600101f46001556103e86000540260010160025500 -fdba06429bd93561b41c5953611bb7ffe0b3b706509a872d20c09606d4a051e2=6000600060006000601773bad304eb96065b2a98b57a48a06ae28d285a71b5620186a0f150600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b56707fffffffffffffff400 6403d40db5100426f4be765613d8db9d58f6b1b276a0d0cffeeff1264b787e8a=6001600054016000556000600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b562036b005a03f160015500 +fdba06429bd93561b41c5953611bb7ffe0b3b706509a872d20c09606d4a051e2=6000600060006000601773bad304eb96065b2a98b57a48a06ae28d285a71b5620186a0f150600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b56707fffffffffffffff400 451d06e323434c52e2a3d65400abaac0b245634eb0f33307723c2e276ac83b32=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350f45060005160005500 a0fe427a36ac004b74ca059fffb2c45e481bd46f564281299e03c66b64dc3a26=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600060006020600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350f45060005160005500 c65245e65a9bed57921028dcb30c7a2e52fde9f6c793fcb24b969f87b997ccda=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052602060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350f45060005160005500 b7e72e1c8d9f2c941bce07dd527a3611514420e00fb57d100819a80c2e09b15e=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600a60006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350f45060005160005500 b2957d2a9eae413e2f05c2b4e1e9105ff1c03459660ffc36c47fd654a988adc9=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600260006040600073945304eb96065b2a98b57a48a06ae28d285a71b56bfffffffffffffffffffffffff460005500 -8205ccbba7ba5cda9ba18d2b743456a5a5ae28c794289b4f7f674e3de3263e9a=346000553360015560003560025500 133de2b241ec3ff88af5e8eb24416f1be967b72c6f8fddb438380ad644f05f4b=60016000526040600060406000731000000000000000000000000000000000000001620186a0f400 +8205ccbba7ba5cda9ba18d2b743456a5a5ae28c794289b4f7f674e3de3263e9a=346000553360015560003560025500 6de5f23423df62287edbcc3ba1da7c482ddf3f82fc9f4b2c02914f94c1f5ad93=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5622dc6c1f460005500 6e6e141f37460a061512b6f252198f61fe0504403956b067297066395f3a70fe=600260006040600073945304eb96065b2a98b57a48a06ae28d285a71b56207a120f460005500 848d6cde8e336967fe91c0806a8fa5b7d7b90c01b3aea951b342540a3b9116c3=604060006040600073945304eb96065b2a98b57a48a06ae28d285a71b561c350f460005500 @@ -1632,22 +1632,22 @@ ffcb314bb59677ab6c9d61dbdc62cf0048c65ce6f887e99d155542035f3672ef=5a6008556000600 1f2652b1c89a3813b6f38ba3dbef143dc331428de3b5ddcf96877c64b391256f=5a6008556000600060006000600073100000000000000000000000000000000000010762030d40f160095500 016d949e2d94b04a422ce01d9b6b8814ac56de8730447894c127d6b34a942b42=5a60085500 68322fd65ffc3848db62898f9a624413c70af4f57322bcfbdb900551fd2f9176=5a60085560006000600060006000731000000000000000000000000000000000000108620927c0f160095500 -cb7f48a28e3b7344d383cd49b2657a0c20bc109c28dd890ec0b313afa643460e=5a60085560006000600060006000731000000000000000000000000000000000000113620927c0f160095500 -5a12bedda1432446b7eec7329b1b305da2685f9444140a847891658049fa929e=5a600855622fffff60002000 e24d0510cfdb27d02652a2093bb0ab7c072a142e875da65ec872c8db043ea87a=5a60085560006000600060006000731000000000000000000000000000000000000114620927c0f160095500 +5a12bedda1432446b7eec7329b1b305da2685f9444140a847891658049fa929e=5a600855622fffff60002000 +cb7f48a28e3b7344d383cd49b2657a0c20bc109c28dd890ec0b313afa643460e=5a60085560006000600060006000731000000000000000000000000000000000000113620927c0f160095500 +e5ea9813b1a45461a2c6b4b4d54e1b2bc84c43492a60e67790431bc764241205=5a60085560006000600060006000731000000000000000000000000000000000000110620927c0f160095500 4a7fd2dbe174b72f892e2a64d82d493c802bb9cb7cd0f499a37bc32903b6e205=5a600855622fffff600020505a6009555a600a5500 7cc4db19afdf9c3ccd33c8f4b8003c832abbaec2de7923147b7b316652b8595f=5a60085560006000600060006000731000000000000000000000000000000000000111620493e0f16009556001600c5500 -e5ea9813b1a45461a2c6b4b4d54e1b2bc84c43492a60e67790431bc764241205=5a60085560006000600060006000731000000000000000000000000000000000000110620927c0f160095500 2fb5ca46ea750c14fff562ff06e6e2ce55b347d6f2bad23cd79f48f076d86148=5a606452635a60fd556000526004601c6000f0600b555a6064510360095500 078aa7a67e05378d2d6a01c7849209aa1e715ff722779ad7236ec0f607cb837d=5a6008526000600060006000731000000000000000000000000000000000000105620927c0f46009555a6008510360085500 15ba436321000c9c5343067ee4a6ae690f10cbdf8bd2839ccb53920beb05667a=600c60015500 e952288bfd7d359e8e6d68c34e8f374ecb9bbc6d3b31bdaceae8a92b6dcda854=60006000600060006000731000000000000000000000000000000000000001620927c0f160015500 -4a20311675b86136b91882212546df94ac5adc617567ceb81b905635606f0c80=5a6103e7527310000000000000000000000000000000000000103b6001556014600060007310000000000000000000000000000000000000103c60005160025560005460045560006000600060006001731000000000000000000000000000000000000011617530f160055560006000600060006001731000000000000000000000000000000000000011617530f26006556000600060006000731000000000000000000000000000000000000011617530f460075560006000600060006000731000000000000000000000000000000000000013617530f160085573a94f5374fce5edbc8e2a8697c15331677e6ebf0b316003555a6103e75103600a5500 eb8e9149bbe1ef10c9bb97aefb652f40040aa4b8b99e6d2bebc607cabc4a6071=601160645500 +4a20311675b86136b91882212546df94ac5adc617567ceb81b905635606f0c80=5a6103e7527310000000000000000000000000000000000000103b6001556014600060007310000000000000000000000000000000000000103c60005160025560005460045560006000600060006001731000000000000000000000000000000000000011617530f160055560006000600060006001731000000000000000000000000000000000000011617530f26006556000600060006000731000000000000000000000000000000000000011617530f460075560006000600060006000731000000000000000000000000000000000000013617530f160085573a94f5374fce5edbc8e2a8697c15331677e6ebf0b316003555a6103e75103600a5500 774633243e64cf3ebc40608cd4a5d4e63aa60c5de4c19caaccb7eea0b2ec60f6=73b94f5374fce5edbc8e2a8697c15331677e6ebf0bff00 d50f384149292a2da6a35604e0c706c197c311494ef9767a50d597f341a7171a=5a6000526000600060006000600073100000000000000000000000000000000000011861ea60f1505a6000510360015500 -fa34d1e0544d9f4d11d1839bded8f96c4357b060adab2f42dce8965629ff5198=732000000000000000000000000000000000000115ff00 6e131966e19f64076f1fb97dc8dfe75255336e26958c64ee9974266d60390329=5a6000526000600060006000600073100000000000000000000000000000000000011661ea60f1505a6000510360015500 +fa34d1e0544d9f4d11d1839bded8f96c4357b060adab2f42dce8965629ff5198=732000000000000000000000000000000000000115ff00 9c6be42daef8d1f2b41ab7e221cbaafb0e2af8d9b7d5bd9c81f98c42e505c386=5a6000526000600060006000600073100000000000000000000000000000000000011862027100f1505a6000510360025500 e3573896039e19c47ed370daf5f6d284a1825e8d8efd0c0a7a1d9c2f6825b2b3=5a60005273a94f5374fce5edbc8e2a8697c15331677e6ebf0b31505a6000510360015500 1e7aa0dd5e3e0ebb8264cc2a31098e1f40f9712dbdea4f8bbf0a274ac956a992=5a60025500 @@ -1711,20 +1711,20 @@ a564c77866beb770e7d04eb1e7b69e1f793642c45d1ceae9b048e4e8700c3554=6160a7600052616 566a2fb3788518dcdbf2b4e84b1242016e317bea37cffb8e50d7d02d940daa2b=5a6000526000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f1505a6000510360645500 1857e39f8922c5c728afc24a2dddb22a1e865a4c101b873e6ee67f639cccac55=5a600052600c60000a6001555a600051036002555a6000526000600c0a6003555a600051036004555a60005267ffffffffffffffff60000a6005555a600051036006555a6000526fffffffffffffffffffffffffffffffff60000a6007555a600051036008555a6000527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60000a6009555a60005103600a555a600052600067ffffffffffffffff0a600b555a60005103600c555a60005260006fffffffffffffffffffffffffffffffff0a600d555a60005103600e555a60005260007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a600f555a6000510360645500 c30b60a297bc114822c8e14df3c876c56add3a4182cf7b987477a5fbef3a6553=5a60005273c94f5374fce5edbc8e2a8697c15331677e6ebf0b3b6001555a6000510360645500 -91e8abf25e107edb430c758a636574a9856b877250a7716180702eb337fc6b0a=6000600060006000600073ee098e6c2a43d9e2c04f08f0c3a87b0ba59079d46000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b6000f100 a19fa2b72a0cc97f6e79cad016c5e9496b86ee450244d51285ba2941cb87ce2b=5a00 +91e8abf25e107edb430c758a636574a9856b877250a7716180702eb337fc6b0a=6000600060006000600073ee098e6c2a43d9e2c04f08f0c3a87b0ba59079d46000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b6000f100 f15d8dd53de81966c3c53f458e7c59bf8ea1a492e92c282f371ccb6b17d67336=60206000f3 -010911570642c8263ecf3e4b9962fd621db6b14ead00e43a01038c8946240fd6=600160005560008060008061271073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af150 +010911570642c8263ecf3e4b9962fd621db6b14ead00e43a01038c8946240fd6=6001600055600060006000600061271073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af150 6837614816f00cdf8a34c7089b92ccfb445c85d3ae39fe52254ad886233e23c6=6001600055600060206000612710f550 f2adcfff8511f649415782700392d85ad868bce9be6bf4cb8182906811455113=600160005560206000612710f050 -1069c043580db2ae345628d5f35ae22d30dd303007850a0bc1c2ef218d351591=600160005560008060008073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af450 -a54dac63f58da9143c7a638921f297db39e67ce2e3ced0e395b20430d1e3d0fb=60008060008061271073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af150 -38500297ffe27de5ec2ee4eaf8acff775637bb8d7f745de2a72837e045571252=60008060008073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af450 -c582eff643ca49efe39fc279b4bd43c2e150e59b643c69470116f65ce1f5f7d1=6000600060006000600073dead00000000000000000000000000000000000162028488f160005573dead0000000000000000000000000000000000013f60015500 +1069c043580db2ae345628d5f35ae22d30dd303007850a0bc1c2ef218d351591=6001600055600060006000600073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af450 +a54dac63f58da9143c7a638921f297db39e67ce2e3ced0e395b20430d1e3d0fb=600060006000600061271073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af150 +38500297ffe27de5ec2ee4eaf8acff775637bb8d7f745de2a72837e045571252=600060006000600073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af450 a335dc68decf7ac526505bee581c3669f6b925204dac27ed9a4661dce408ea2d=600060006000600073dead00000000000000000000000000000000000162028488fa60005573dead0000000000000000000000000000000000013f60015500 b0186d1f0fb83cab30598535b1d61a06b4d5b7d4f30f54ce0baa5c36b6168a5c=6025ff00 e4d13dbb224dfb3c5baa06f80b928b029ae49a326d7f4dc4931dcd2e18fe1b74=6000600060006000600073dead00000000000000000000000000000000000162028488f260005573dead0000000000000000000000000000000000013f60015500 0d3135ebc4586f22e79775adca28a939f1dad92378cc4e56b65d2748ab8ddb29=604060006040600060006000355af200 +c582eff643ca49efe39fc279b4bd43c2e150e59b643c69470116f65ce1f5f7d1=6000600060006000600073dead00000000000000000000000000000000000162028488f160005573dead0000000000000000000000000000000000013f60015500 07f57c2882d785f5e00721021ade0111a4ad7f5731d8e446856cb5f81b811b0a=600060006000600073dead00000000000000000000000000000000000162028488f460005573dead0000000000000000000000000000000000013f60015500 2fbb4625057c201a4e9d2f25d41fc8231f598df1013a01cc5a8d38747f8d9878=60206000600073a2220000000000000000000000000000000000003c60005160105573a2220000000000000000000000000000000000003b60115573a2220000000000000000000000000000000000003f6012556000600060006000600073a22200000000000000000000000000000000000061c350f260135560206000600073a2000000000000000000000000000000000000003c60005160205573a2000000000000000000000000000000000000003b60215573a2000000000000000000000000000000000000003f6022556000600060006000600073a20000000000000000000000000000000000000061c350f260235560206000600073a3000000000000000000000000000000000000003c60005160305573a3000000000000000000000000000000000000003b60315573a3000000000000000000000000000000000000003f6032556000600060006000600073a30000000000000000000000000000000000000061c350f26033556020600060006000600073a10000000000000000000000000000000000000062086470f15060005160405500 9655ae0666d5d46da6ef913c73b969ffdd36c5adb6f19bfe83c6bfbe47f1568f=6000603980601a60003960006000f560005260206000f30000fe60206000600039600051605055303b605155303f605255600060006000600060003061c350f23b605355602060006000303c60005160545500 @@ -1736,9 +1736,9 @@ e4c17df96db7198923adbb3613fb06daf08df364dd4eaefea23f979186b7924d=600b60505500 156633606cec03dd7aa5cbba790a1391e1d3cf2eaecfad59f006d7480258ee68=6020600060006000600073deadbeef00000000000000000000000000000000620249f0f1506020600060003e6000516000556020600060006000600073aeadbeef00000000000000000000000000000000620249f0f1506020600060003e60005160015500 82651f83a3f20bc5f22127f2f83e9e046389754ea52cbffeff2615a12d326cf5=73deadbeef000000000000000000000000000000013f60005260206000f300 7d479463e5816548703f295fb2cc82613af84454eb6d339fe3ed819215d2212b=73deadbeef000000000000000000000000000000013b60005260206000f300 -62d393661b8ff460bab64febc392284589fd4a4cff568e32c3c13de085552b74=73deadbeef000000000000000000000000000000013b60005260206000f300 fd3a9c1e19e63f147b68a35c11172ee7136a4310e5d938cf45faf4b24146e5e9=6020600060006000600073deadbeef00000000000000000000000000000000620249f0f2506020600060003e6000516000556020600060006000600073aeadbeef00000000000000000000000000000000620249f0f2506020600060003e60005160015500 68ff1831256501f492cf7e85526c3b0e356d95fa9ca755db1f3714349b04f050=73deadbeef000000000000000000000000000000013f60005260206000f300 +62d393661b8ff460bab64febc392284589fd4a4cff568e32c3c13de085552b74=73deadbeef000000000000000000000000000000013b60005260206000f300 b6b7e12f5a976593684d319b348150b69549ce23fb21eaaf5b71a2e7f8730bf6=6020600060006000600073deadbeef00000000000000000000000000000000620249f0f1506020600060003e6000516000556020600060006000600073aeadbeef00000000000000000000000000000000620249f0f1506020600060003e60005160015500 e483c6077f21978e25ee7e35054786b2a769babf998f275b37370e99df528c8d=73deadbeef000000000000000000000000000000013f60005573deadbeef000000000000000000000000000000013b60015560006000600060006103e873deadbeef0000000000000000000000000000000162010000f15073deadbeef000000000000000000000000000000013f60025573deadbeef000000000000000000000000000000013b6003550000 45b5782e03b97c0637e4926e532285d223e5358cdd8b2d9b1c0558f5496a5ab3=600060006000f05061123460005500 @@ -1800,12 +1800,12 @@ ee7da33709c19bd962eee68389c89314f6ec80137d3441cb78d6c111a4027308=74600c600055666 509b43ac8411dbf966c230b9f8dd35c152414b7be1c848a8bebb1da34cb58353=3060025560206000600039602060006000f000 c21ce7b52ab574f79ada30926ebda6e9f60641c8985aafee8dbaae36f687c35f=602060006000f000 9697d016645564aeb2639c2d88c07e6954b66c78b4e4319d1030e7591481b591=600980601160003960006001f0500000fe621122336000550000 -b4387f4c142f0127da220e06eacce7c746b6bbee86fcab846173ebfb1f108f9b=60156000526020602060206000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b611b58f15060005160005560205160015560406000f300 3ee127d91eea32240afe65fc76abd217b294a9645f1bb8dcbddda48bb07e9d57=60003560030260005260206000f300 +b4387f4c142f0127da220e06eacce7c746b6bbee86fcab846173ebfb1f108f9b=60156000526020602060206000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b611b58f15060005160005560205160015560406000f300 e3ec67bda76132618ccf43c96cb0cf44bcf28757f2c8595217290fd11e4a7988=60156000526001601ff300 b02b73e0457e3cdff66bcdce1be234608caa8fb50cf3cf31086b54fe03ff5eab=6001601f6001601e600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6107d0f1506000516000556002601ef300 -df423a926a6db526900013c97c1e27cec738a0c18a441b152adafb975c79e1c2=60006000a000 8902038f59677d0f2f76aec116db122a94b1b364cdadafb02af511ab035e30eb=60006000600060006017730f572e5295c57f15886f9b263e2f6d2d6c7b5ec66103e8f160005500 +df423a926a6db526900013c97c1e27cec738a0c18a441b152adafb975c79e1c2=60006000a000 f6f233f954759153a90af5be5b90fdec95b9df6818174f60f0a0497bb0291117=7faabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd60005260017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa000 56e86c9da13b58772b3e014e61121aae77642ace0a6ee9bb3b7feb9496581def=7faabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd6000527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001a000 49ba9ec8d6537b838d9b4e3a3dc60731eb96782bb565e84a530856908c296d52=7faabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd60005260006001a000 @@ -1855,8 +1855,8 @@ d04d9233925cf1a3991f0848c9c7fe98a2984dd8dfdf09f76309330759eb2f0b=7faabbfffffffff 399fe86cade164b82ac638f669b21249d01d6a52bb537fe65152c0737457eddf=63dead60a76000526101006000f300 ac71ea1958b7e077fbfc3c8e16602315e0d77e77e36856e7d150c159266858da=63dead60a76000526101006000fd00 46ce285cc3af557e8194e718100c3ae4c9c82b85b48cd9c7a9b891c902e2bb86=60043561012052602435610140526360a760a760005261010060006000600060006101205173ccccccccccccccccccccccccccccccccccccccc00161014051f16101005260005160005560003d116057576000506060565b602060006101603e5b6101605160015500 -8ccf19d65aab653a0aa9489691349aec03a45fa6cfc046110f327dec627084e8=630fffffff630fffffff630fffffff630fffffff60007310000000000000000000000000000000000000016707fffffffffffffff200 7d73b53969b64e0a95ec98b7562644ccd76661044d654aa5a5790dd8428bb4c6=60005460010160005500 +8ccf19d65aab653a0aa9489691349aec03a45fa6cfc046110f327dec627084e8=630fffffff630fffffff630fffffff630fffffff60007310000000000000000000000000000000000000016707fffffffffffffff200 064c87204cf39627b92357a24043959f79dbfac6a8f962672c5790969e86aff2=63ffffffff63ffffffff63ffffffff63ffffffff60007310000000000000000000000000000000000000016707fffffffffffffff200 584c831d0ad95dc1b1a2fa111cd90fb80e843c25b95f052ad877021b62e171c7=67ffffffffffffffff600067ffffffffffffffff600060007310000000000000000000000000000000000000016707fffffffffffffff2506fffffffffffffffffffffffffffffffff60006fffffffffffffffffffffffffffffffff600060007310000000000000000000000000000000000000016707fffffffffffffff2507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600060007310000000000000000000000000000000000000016707fffffffffffffff25067ffffffffffffffff67ffffffffffffffff67ffffffffffffffff67ffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff25067ffffffffffffffff67ffffffffffffffff67ffffffffffffffff67ffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff2507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff2506fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff200 5eedf45cf7035da00c6c38686d1b3773cb6d615a2826065c6c608906813459d0=600060006000600060007310000000000000000000000000000000000000016707fffffffffffffff250630fffffff6000630fffffff600060007310000000000000000000000000000000000000016707fffffffffffffff25063ffffffff600063ffffffff600060007310000000000000000000000000000000000000016707fffffffffffffff2506000630fffffff6000630fffffff60007310000000000000000000000000000000000000016707fffffffffffffff250600063ffffffff600063ffffffff60007310000000000000000000000000000000000000016707fffffffffffffff250600067ffffffffffffffff600067ffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff25060006fffffffffffffffffffffffffffffffff60006fffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff25060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff200 @@ -1879,23 +1879,23 @@ fe915acef64713ed78a436609d597a9515a122a544222751638161e50026ea40=600164fffffffff f2e3f4df6f5b48738fe1a4dbd5aea8f72b4842797a0b5d207977b9654e8573fd=6001623fffff5200 0cae2e21896571f1d0482a40f66e06729ad32ae86e9440c19e452d563d593597=600167ffffffffffffffff5200 47a126462863e1fc487df67bab3df2089abfc71aa4b523f7b6782ae90825600b=60005063ffffffff5067ffffffffffffffff506fffffffffffffffffffffffffffffffff507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5000 +386fe076c477ec967131a49281dbba375b51925bb4430042079e8915798b9348=67ffffffffffffffff6000f300 +6a6e213b3e7eb57ceb0bb22c17e461767dcb28d94c1b903eb304dcf95bb41c61=6000630ffffffff300 +78905e9e7a45f8598e6b7867c3adc15240d24277e35d8c16f2db09cdc1544975=60006d0ffffffffffffffffffffffffffff300 +8408466c1816cc59b6b9fcec7e37aea7164604a0df94e1e30831c9423886c817=6d0fffffffffffffffffffffffffff6d0ffffffffffffffffffffffffffff300 +4c1bdd3575d4730e3f56181077c12ee35942e531c8bf25e5a917af08eae5539d=630fffffff6000f300 +00d5de551ee7a5a4b93cfcfd0a3e939c901ba44f1121cb499f3f906f32307c78=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000f300 +89a733741df289bcde6ceec5cf1bea1bd3c58eadc58c72fed47657d554a23ecb=60006000f300 +d679f961d83db60ac5f3be30a471dda0a7670a8b011a9e6390e8cca98bec5b62=600067fffffffffffffffff300 0b89d04832122a7a3e9bff16f2c29dcd664ae3018605a456f43030cff862c3e6=60007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff300 +3eb1e695975e52e7dd4f7afffe8b02fca385f966034c7be4ed277d9c596208ee=600060006000600060007310000000000000000000000000000000000000016707fffffffffffffff1600155600060006000600060007310000000000000000000000000000000000000026707fffffffffffffff1600255600060006000600060007310000000000000000000000000000000000000036707fffffffffffffff1600355600060006000600060007310000000000000000000000000000000000000046707fffffffffffffff1600455600060006000600060007310000000000000000000000000000000000000056707fffffffffffffff1600555600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600655600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600755600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600855600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600955600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600a55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600b55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600c55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600d55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600e55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600f55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff160105500 eed3ff87a0d0c61b833776c14ef3fba65cc145a1bcc2a914d4226781c9ec623c=63ffffffff63fffffffff300 -d679f961d83db60ac5f3be30a471dda0a7670a8b011a9e6390e8cca98bec5b62=600067fffffffffffffffff300 -89a733741df289bcde6ceec5cf1bea1bd3c58eadc58c72fed47657d554a23ecb=60006000f300 -4c1bdd3575d4730e3f56181077c12ee35942e531c8bf25e5a917af08eae5539d=630fffffff6000f300 -b4d880e59c7c17bc74784c186bde67430d3ddb71a778a98eda8c7122d56b653c=6d0fffffffffffffffffffffffffff6000f300 -6a6e213b3e7eb57ceb0bb22c17e461767dcb28d94c1b903eb304dcf95bb41c61=6000630ffffffff300 4134e61bba4b29954deb6977e3c14a40dafd92ddb73461f86413c2e18d0e4904=67ffffffffffffffff67fffffffffffffffff300 -00d5de551ee7a5a4b93cfcfd0a3e939c901ba44f1121cb499f3f906f32307c78=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000f300 -78905e9e7a45f8598e6b7867c3adc15240d24277e35d8c16f2db09cdc1544975=60006d0ffffffffffffffffffffffffffff300 +f1cc4f74ba159815e4fd2c1e19cc1dbac964dda4b45bf47ccfe0e029852358ef=63ffffffff6000f300 46a54a35478ad25df50ebc2b6f7550b25b7451b343fb8c1e08b141b4ce751547=600063fffffffff300 -386fe076c477ec967131a49281dbba375b51925bb4430042079e8915798b9348=67ffffffffffffffff6000f300 +b4d880e59c7c17bc74784c186bde67430d3ddb71a778a98eda8c7122d56b653c=6d0fffffffffffffffffffffffffff6000f300 317476e600a0d257f84d0f46262ccfbc9acd728b996b9e560551ac22c4900860=630fffffff630ffffffff300 -3eb1e695975e52e7dd4f7afffe8b02fca385f966034c7be4ed277d9c596208ee=600060006000600060007310000000000000000000000000000000000000016707fffffffffffffff1600155600060006000600060007310000000000000000000000000000000000000026707fffffffffffffff1600255600060006000600060007310000000000000000000000000000000000000036707fffffffffffffff1600355600060006000600060007310000000000000000000000000000000000000046707fffffffffffffff1600455600060006000600060007310000000000000000000000000000000000000056707fffffffffffffff1600555600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600655600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600755600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600855600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600955600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600a55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600b55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600c55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600d55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600e55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600f55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff160105500 ff821a70b5e78b13b36cf3e507408b602fdefa2af105e07b7f8ab49f1dd2ad3a=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff300 -8408466c1816cc59b6b9fcec7e37aea7164604a0df94e1e30831c9423886c817=6d0fffffffffffffffffffffffffff6d0ffffffffffffffffffffffffffff300 -f1cc4f74ba159815e4fd2c1e19cc1dbac964dda4b45bf47ccfe0e029852358ef=63ffffffff6000f300 9af366a03b359821a8029b03699c4ab4e3bdc8ed02cab79a9cdf4a36fe915bac=6000545063ffffffff545067ffffffffffffffff54506fffffffffffffffffffffffffffffffff54507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5400 883a7f1d89643b1d3f3d73e32f11083eec85093215e3195184dce5cd758a89d1=600163ffffffff55600167ffffffffffffffff5560016fffffffffffffffffffffffffffffffff5560017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5563ffffffff60205567ffffffffffffffff6040556fffffffffffffffffffffffffffffffff6080557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101005500 ff631084ef91e3ef02af7701b65c7849f05e96278f62e502bce19f156459080b=6401773594005160015500 @@ -1905,8 +1905,8 @@ e2b739e3e9aee02a6540cdfc27b5b6cc26ab2c574857b23db6235f224f676592=600160005263fff 9e915990c251fb9a282d74e6fbaea9bc9d69565ddb7da2592dd0ba2b8326b408=63ffffffff6000f300 e82976f19147f4b453ca8b58f9be648e9c40de237fa944ce6cce004794db8a40=630fffffff630fffffff630fffffff630fffffff7310000000000000000000000000000000000000016707fffffffffffffffa00 c4685fdab5c0cb3684ee14a4f16fb05bdb7706f8122aa0fd95ecbd197894ca0e=63ffffffff63ffffffff63ffffffff63ffffffff7310000000000000000000000000000000000000016707fffffffffffffffa00 -266d50413b3526c6d6db3488bbe86c35500a9fca848732b9704a5a6573083583=67ffffffffffffffff600067ffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa506fffffffffffffffffffffffffffffffff60006fffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa5063ffffffff63ffffffff63ffffffff63ffffffff7310000000000000000000000000000000000000016707fffffffffffffffa5067ffffffffffffffff67ffffffffffffffff67ffffffffffffffff67ffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa506fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa00 f1e2e5150310bd12b688199b146ce34bf0e03758d5c911f0069a8cdcfbcb4292=60005460010160005200 +266d50413b3526c6d6db3488bbe86c35500a9fca848732b9704a5a6573083583=67ffffffffffffffff600067ffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa506fffffffffffffffffffffffffffffffff60006fffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa5063ffffffff63ffffffff63ffffffff63ffffffff7310000000000000000000000000000000000000016707fffffffffffffffa5067ffffffffffffffff67ffffffffffffffff67ffffffffffffffff67ffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa506fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa00 c69e6a67ecbf69e8d1d465b762944371857db02d1485df69f2ec8ea24d98fccc=60006000600060007310000000000000000000000000000000000000016707fffffffffffffffa50630fffffff6000630fffffff60007310000000000000000000000000000000000000016707fffffffffffffffa5063ffffffff600063ffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa506000630fffffff6000630fffffff7310000000000000000000000000000000000000016707fffffffffffffffa50600063ffffffff600063ffffffff7310000000000000000000000000000000000000016707fffffffffffffffa50600067ffffffffffffffff600067ffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa5060006fffffffffffffffffffffffffffffffff60006fffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa5060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa00 02b70170ddbf89061c6a8c7bb91a023ca494b643c0d63ec0efa75ea1c07421ac=6101206000f300 3c4e35c17317d029fa326f619b7d5fa854bfc5c5d207e3b040d4e284c6c47133=6000600055600035602035f300 @@ -1955,15 +1955,15 @@ b2f34f8fd7351af42946f10cbcbaceabb764e90e0f230d4bde11fa12195ad688=602a61f9e053596 3128fa92bfdd224510dfdf841a34b464559eb1ab297d8f5d4c68c16514e1aae6=602a61f9df535960005500 936f52989634c9dc92d33ba901a5ac808bc9acd93db45d9b7eba773c496490fb=602a61f9de535960005500 d4f7e542342692e64b86707702652e79e04b253edfa91cdd1a6f0bbd3efbb0d8=602a61f9ff535960005500 -2008b8b4aea344d1383a53ece06a0db6166b4133f10877fdf922b9998cce5731=600460005b600f811015601f576011600182010281536001810190506004565b50600051600055600a6002600a600080855af150600051600155600a600060203e60205160025550 +2008b8b4aea344d1383a53ece06a0db6166b4133f10877fdf922b9998cce5731=600460005b600f8110156020576011600182010281535b6001810190506004565b50600051600055600a6002600a60006000855af150600051600155600a600060203e60205160025550 c367c64d90ffa50458cf755dc5d10f83bc2d9d8250058d3d05b943468aefa07e=366000600037596000f300 7012bc42bb8026cf166f7326ed246b0f95e4f751c2e5cf9c08dad4f0d7047b2e=620100005160015500 0898f33abc8db9ff3da67ce0a69db61613ce641395635c11fa1517790e7d6dc7=6101005160015500 a9e5d35726cf7d3f99d83c391100c936092c87831b690d033d14da5db51bf170=61100060002050 -9ef622c9b42196fe0519fda0941f998d4d99a6a175c9005b7097c2903217b31d=61100060008037 -28913a4f566a2dc5e3ac457a4eaeccbf06bbefa53f18a652b15e10dfb271bfb9=61100060008039 -5e2b9eeb0294a6acad85d6c1e76bdb6d37df823ec31f36660d850cd903ae67ff=611000600080303c -55c5e2cef947d4612f1729e73b33e00c5ff964879895947e26937d916a5e939b=6020600060206000806201113e5af150601060006110003e +9ef622c9b42196fe0519fda0941f998d4d99a6a175c9005b7097c2903217b31d=6110006000600037 +28913a4f566a2dc5e3ac457a4eaeccbf06bbefa53f18a652b15e10dfb271bfb9=6110006000600039 +5e2b9eeb0294a6acad85d6c1e76bdb6d37df823ec31f36660d850cd903ae67ff=61100060006000303c +55c5e2cef947d4612f1729e73b33e00c5ff964879895947e26937d916a5e939b=602060006020600060006201113e5af150601060006110003e e499501e5bafbd1c361c20dc5a05e40c7d486d5ab46cf9e2cfd59346786b9b38=7f0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2060005260206000f3 13d0233a2bd697f7398d45c35017fc346a4b6f6b9accef673effad9d91a5c92f=6110005150 10cfa4256c7bf2c8801020effb7b4d90f16681520073bf48f4b0aaab4c3b70b8=60ff61100052 @@ -1976,11 +1976,11 @@ c15fc1157326db732bdd5e728ae4f8c71f30a379e40db53a60cd1a63e6b1a89b=600460036002600 b439c2fe865f899a9b489a5f79a04101534669e9d6b7051df6f16083dd5c160e=6020620100006000f050 b4ba69d5a16b5e51f0e17fbfd2225ea8c2eb959a74162c79e3b85783dadd9fde=615a176020620100006000f550 1b2290979cf403b8281ad39f910906c10e8953e8048d40dc38623dff8007c8b9=602062010000f3 -2ecc7534ab3ed062c9e731421cad45f819bb031262794a81addffc46def2fa03=6000806000620100006000620111f15af150 -26210b12ec0faac7a4d6c0d0b55aee7569965df3ff695be9895e27f6e3d7f533=6000806000620100006000620111f15af250 -d93eddd86ce9004dfd9651ee2531a49a39dd41e2e4335266970443a8c3fd841a=600080600062010000620111f15af450 -187f3a42d83cff10533684fecfc325133b872195c7a3b8d777b2a70c670e2ad6=600080600062010000620111f15afa50 -74137ced833d5efd3e225bc476c503830692634aa1932401210e2f8fb533e2fb=600435602435600080600080600086620100000186f16000555050 +2ecc7534ab3ed062c9e731421cad45f819bb031262794a81addffc46def2fa03=600060006000620100006000620111f15af150 +26210b12ec0faac7a4d6c0d0b55aee7569965df3ff695be9895e27f6e3d7f533=600060006000620100006000620111f15af250 +d93eddd86ce9004dfd9651ee2531a49a39dd41e2e4335266970443a8c3fd841a=60006000600062010000620111f15af450 +187f3a42d83cff10533684fecfc325133b872195c7a3b8d777b2a70c670e2ad6=60006000600062010000620111f15afa50 +74137ced833d5efd3e225bc476c503830692634aa1932401210e2f8fb533e2fb=6004356024356000600060006000600086620100000186f16000555050 caf9facbed862fe613b3320022ed06b17a8dca8eacc2c73de4713f009ae469dd=5a6000526000600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f26001555a6000510360645500 c7a6d05c0caf2c88e24e84509b2b882162e24a3c66f8e17d5f0a9b93a7ee5e4b=5a6000526000600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f16001555a6000510360645500 4366d37cfc4ffc877c93c4b6b4c5c7334203a7532f95d17ed0b69f11c4817573=5a600052600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f46001555a6000510360645500 @@ -1993,9 +1993,9 @@ f01c97341686169e115128bc4a55d9714e85d3f05bb3c2c5764afeb983e04c6f=600154506002545 044661348c230fea4bf2ff442a4422738b9b9ebbef430f09273aec57fec16952=600154506002545061ffff60020a600a553031600b5560006001556000600255600060035560006004556000600555600060065500 b1ec84eb90eb693cdbff9a5ac86f8f729e3ef784bf36384c730ba39d1b10dda0=73ddddddddddddddddddddddddddddddddddddddddff cd8bcc7a2b45eedecfdb09569a86e3148578de2e210b26bb4cf3f862bbd3a062=6000806000558060015580600255806003558060045580600555806006558060075550 -2e8d8a457543cf940ef631ca98fcfd11c5cb1119d2e6d6eda3efb2a8a1c5d674=60008055 -4ded1eb002cb054874f2ea1996edd56bd3da577953433c9aaa702976cd608321=5a6016526001600a556000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa600035f1600b55600060015560006002556000600355600060045560006005556000600655600060075560006008555a6016510360175500 +2e8d8a457543cf940ef631ca98fcfd11c5cb1119d2e6d6eda3efb2a8a1c5d674=6000600055 f1e3bd42875da1d50d5f6ee47b7c3a81cdfa546ce482edf6cd3e276d661e27f4=73095e7baea6a6c7c4c2dfeb977efac326af552d87ff00 +4ded1eb002cb054874f2ea1996edd56bd3da577953433c9aaa702976cd608321=5a6016526001600a556000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa600035f1600b55600060015560006002556000600355600060045560006005556000600655600060075560006008555a6016510360175500 a6524cc4b8de915b5b279f9b2f6591f15af39ee9f677579cdbbebd9eeba36913=600060015500 6c0bee772d21bb9572e13fba061d867af488ce4c4799703b5c1953648cc1cbd7=6000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa61157cf160005500 b6a870e429c801eacf3617f4a0c5705161fc4b18909b049f784cc616cd3d6001=6000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa611770f160005500 @@ -2007,23 +2007,23 @@ f138dcfed5bbdbd7e4b21866ccb59e0ee6f66d493dbc9f4445c64b313aeed11e=60aa60006000600 d5b367e8600704385458fb4001e9f55a8fa2f57d7f861f0f4bfc53162c24de37=60206000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f150600e80603c60003960006000f0503d6000550000fe6211223360005260206000f30000 c3aaa46b1bcad7e65b2f93c8d62b8ddf023c2217dae18d3542b31fa445897e9b=60206000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f150602060006000600065ffffffffffff730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f1503d60005500 ecd1d96f20e09e6de52af48896e1e955214fdfc84299aa74e6f22bc31818e538=60006000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f150600e80603c60003960006000f0503d6000550000fe6211223360005260206000f30000 -161997d4cd71eeac3a1229ed1334818012302b0e4fde1db26818bd6a499c7acb=6000356160a7600052806000f3 -708e124a9dd48d3f9fed7de053464e4a73b23a3b11270d7dd3ecd3078915663e=6000356160a7600052806000fd -8fc69ebe56dd2a6b658881e1287c49a7966486390dc49bea82ed4228f571c71b=60003560203560403581600052602060006020600080875af1503d6000553060015500 -ca4a5d2e59e72586a296c5928c1ad18abd1d5ee9dcee43c3bd4c6c6472a23025=60003560203580600052602060006020600080865af150307846455050 -293709612af3fad0c2119caac70779499e03a1e504e1a316b6e0161a77b9e34e=60043560243560443560006100cc565b6000607f60005382600152606060215360006022536052602353606060245360ff60255360606026536020602753606060285360206029536060602a536000602b536060602c536000602d53607f602e5381602f52605a604f5360f1605053606060515360206052536051605353606060545360006055536055605653603d605753606060585360016059536055605a536000605b53605c905092915050565b60006100bb838361000f565b60fe60018203538091505092915050565b8360f08114610138576111f0811461014f5760f58114610166576111f581146101805760f1811461019a576111f181146101b85760f281146101d7576111f281146101f55760f48114610214576111f481146102315760fa811461024f576111fa811461026f57600080fd5b610142838561000f565b915081600080f050610289565b61015983856100af565b915081600080f050610289565b610170838561000f565b9150615a1782600080f550610289565b61018a83856100af565b9150615a1782600080f550610289565b83600052826020526020610100604060008062ca11ed5af150610289565b83600052826020526020610100604060008063bad0ca115af150610289565b83600052826020526020610100604060008062ca11ed5af250610289565b83600052826020526020610100604060008063bad0ca115af250610289565b836000528260205260206101006040600062ca11ed5af450610289565b836000528260205260206101006040600063bad0ca115af450610289565b83600052826020526020610100604060006557a700ca11ed5afa50610289565b836000528260205260206101006040600063bad0ca115afa505b503d60005560005160015550505050 +161997d4cd71eeac3a1229ed1334818012302b0e4fde1db26818bd6a499c7acb=6000356160a7600052806000f350 +708e124a9dd48d3f9fed7de053464e4a73b23a3b11270d7dd3ecd3078915663e=6000356160a7600052806000fd50 +8fc69ebe56dd2a6b658881e1287c49a7966486390dc49bea82ed4228f571c71b=6000356020356040358160005260206000602060006000875af1503d6000553060015500505050 +ca4a5d2e59e72586a296c5928c1ad18abd1d5ee9dcee43c3bd4c6c6472a23025=6000356020358060005260206000602060006000865af150307846455050 +293709612af3fad0c2119caac70779499e03a1e504e1a316b6e0161a77b9e34e=60043560243560443560006100ce565b6000607f60005382600152606060215360006022536052602353606060245360ff60255360606026536020602753606060285360206029536060602a536000602b536060602c536000602d53607f602e5381602f52605a604f5360f1605053606060515360206052536051605353606060545360006055536055605653603d605753606060585360016059536055605a536000605b53605c90505b92915050565b60006100bc838361000f565b60fe6001820353809150505b92915050565b8360f0811461013f576111f081146101575760f5811461016f576111f5811461018a5760f181146101a5576111f181146101c45760f281146101e4576111f281146102035760f48114610223576111f481146102405760fa811461025e576111fa811461027e5760006000fd610298565b610149838561000f565b91508160006000f050610298565b61016183856100b0565b91508160006000f050610298565b610179838561000f565b9150615a178260006000f550610298565b61019483856100b0565b9150615a178260006000f550610298565b8360005282602052602061010060406000600062ca11ed5af150610298565b8360005282602052602061010060406000600063bad0ca115af150610298565b8360005282602052602061010060406000600062ca11ed5af250610298565b8360005282602052602061010060406000600063bad0ca115af250610298565b836000528260205260206101006040600062ca11ed5af450610298565b836000528260205260206101006040600063bad0ca115af450610298565b83600052826020526020610100604060006557a700ca11ed5afa50610298565b836000528260205260206101006040600063bad0ca115afa505b503d60005560005160015550505050 bdf500c86f231800385106c4eab9f4a9e0ec938f514e501fc7d35bb7683fac51=602380601560003960006000f0503d6000550000fe62112233600052602060006020600060006004619000f1503d60005560206000f30000 b051a2695de61dc1f8fe6c50384ffabd135e0c645c1fccdee63eb37c18ad7741=36600060003760206103e8366000600060055af26001556103e8516002553d60035500 f8f5b19526c9d84bc95117b16831037cb97126b1444a88bb23ec93ceb035aba7=600780601d60003960006000f0506000600060003e60006000550000fe60016000550000 87717fca55e893cef3f3914ec90aaaba3bfc968d16f510da898ed603d52d8a1c=69600260005260206000fd600052600a60166000f0503d6000556020600060003e60005160015500 28ad3e121d9589a67147605913b360a2e0d50fccfab6b2ee0465931f34c941d8=600060006000600060007310000000000000000000000000000000000000026000f2506020600060003e60005160005500 758e92cde37c427e1b07b24d2ef29eedf1b4d7d751fdc6a810f72b7a0778c419=6000600060006000731000000000000000000000000000000000000002612710f4506020600060003e60005160005500 -dd3bbb7ecc8bfd78bf710b1255cf3b301b0a756ab260ec6d876cc0307cd36e7e=60006000600060007310000000000000000000000000000000000000026000fa506020600060003e60005160005500 00c441f2b4e2a23fda7eef407948ba235b74a414dff979b1561064945069f5b8=3360005260206000f300 +dd3bbb7ecc8bfd78bf710b1255cf3b301b0a756ab260ec6d876cc0307cd36e7e=60006000600060007310000000000000000000000000000000000000026000fa506020600060003e60005160005500 cd446ca1ba0c4d0e1eb1ec088cc54e93e9612e3d4c9c338fe91af58937f70b8f=600060006000600073100000000000000000000000000000000000000261ea60fa506020600060003e60005160005500 8adbfbd72997442672335696caa60cf9b9b8e01e77de1376075c8d4e1c9a5717=3360005260206000fd00 -2ced4da970e939336a948595b4f5cce901ea7d5ee9d5d7ff7b7e36681b548386=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000f300 105560c2675c8add352fd3988fb3b2102447185de01fda631f740ca38f5cbc6b=6000600060006000600073100000000000000000000000000000000000000261ea60f2506020600060003e60005160005500 +2ced4da970e939336a948595b4f5cce901ea7d5ee9d5d7ff7b7e36681b548386=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000f300 c9da6b2267bf1df2805231660fe98266cfe9d714998e507390e60330f3263f0d=600060006000600073100000000000000000000000000000000000000261ea60f4506020600060003e60005160005500 5060f04aaabe7f06a6359e3a1f732141d3dee099d8604a7d96bd47f04d142e2d=60006000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f1506020600060003e60005160005500 bc41a1d08d89f9c286a585d00ab125c327a6af22694673d7fe8f7d8b40d7e990=6000600052596000526002806028600051396000516000f0506020600060003e60005160005500fe0000 @@ -2046,8 +2046,8 @@ fe0af8e75cf2e035b8b23bfbed37332c3925a20a60bca0e51fb94cc4ccfc0e24=602060006000600 f35e49c73c0a888b6c0e443c097739497fafe4035143a02e35447272c4653ac6=6000600060006000600073100000000000000000000000000000000000000261ea60f2503d60005500 1b5310e67a245b79d0ab8131e41c822ee4e1ce46448d8b473dbcf074e339bff6=600060006000600073100000000000000000000000000000000000000261ea60f4503d60005500 185f20ff61caf8d7018cb183bbedf3679658fb8c5ed5af5adbeefbade8144956=3360005260146000f300 -61ad6db59417ebd7b09a5c7831d035277b13ed9ccaf902dc554911285e0f7683=600060006000600061c350731f572e5295c57f15886f9b263e2f6d2d6c7b5ec66001f1503d60005500 9ce395ea9d8983ea96b855c7295a9fb0eb0765cf768bc7c8e6bfaf6570e82896=600060006000600061c3506001600af150600160015500 +61ad6db59417ebd7b09a5c7831d035277b13ed9ccaf902dc554911285e0f7683=600060006000600061c350731f572e5295c57f15886f9b263e2f6d2d6c7b5ec66001f1503d60005500 4d421b7cf93e7f40f00c1550a5a230f35f398e061f5bfd4d5866a8b807da62c0=600e80601560003960006000f0503d6000550000fe6211223360005260206000f30000 3e8e081bbde4c7bceffb768abbaef57dffec021049d0b152ed1aa89a645184eb=3d60005500 840e4db4d3b170831b6679c863c2a54133deaa2ece07122ae5ef07f1634252f9=6000600060003e60005160005500 @@ -2056,11 +2056,11 @@ e100f08670c1c78b59351c33526f8d7eb4e4abeaace4bde8f8f9a65e826d905f=600260016000030 518779d7b59baf1ff9c3c45cff398e12ae2d88511da81ec16f9a0dd9e8b32c6d=600c600060006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f1506000516000556000600052600c60006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f4506000516001556000600052600c60006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40fa506000516002556000600052600c600060006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f2506000516003556000600052600c600060006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f1506000516004556000600052600c60006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f4506000516005556000600052600c60006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40fa506000516006556000600052600c600060006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f25060005160075500 ff06284e0407bdc49c5eef8b55970f90a62e18cdf210a830c4f834f91a71f994=7f11223344556677889910111213141516171819202122232425262728293031326000527f333435363738394041424344454647484950515253545556575859606162636460205260406000f300 a4cb6609f02e609855d0ae4469bc0c2dc008e0b6b77906b9622eb50e147b4a22=7f11223344556677889910111213141516171819202122232425262728293031326000527f333435363738394041424344454647484950515253545556575859606162636460205260406000fd00 -a803bfe42bdb99fe3090d66eefe6c6992f5677953c520ec7ece5b5a4b8b928db=6000357f1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201ff60005280600055806000f3 -9fb65906349b75182a0aea5e5020ca92c4bff64eba948b986bb4ba18caf322de=6000357f1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201ff60005280600055806000fd -0f73f356d63d54c487e160fe69035f674a815e71913d266052f8b5a35b4e2b64=6004356024356044356064358360005261010060006020600080855af182846101003e61c0de3b60200160008061c0de3c3660200160008037386020016000803961dead6000555050505050 -47513d8ba80f62468bedeb52e4a41afafa57013079eb37939861f95d5c98f578=6001600054016000556000600060006000600073a0000000000000000000000000000000000000005af100 +a803bfe42bdb99fe3090d66eefe6c6992f5677953c520ec7ece5b5a4b8b928db=6000357f1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201ff60005280600055806000f350 +9fb65906349b75182a0aea5e5020ca92c4bff64eba948b986bb4ba18caf322de=6000357f1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201ff60005280600055806000fd50 +0f73f356d63d54c487e160fe69035f674a815e71913d266052f8b5a35b4e2b64=600435602435604435606435836000526101006000602060006000855af182846101003e61c0de3b6020016000600061c0de3c36602001600060003738602001600060003961dead6000555050505050 4eef5052b492b54594df3d7ba37b5b619fc81a63981dbe3e5ded7115c51644f8=6001600054016000556000600060006000600073b0000000000000000000000000000000000000005af100 +47513d8ba80f62468bedeb52e4a41afafa57013079eb37939861f95d5c98f578=6001600054016000556000600060006000600073a0000000000000000000000000000000000000005af100 995aee3e8c5b5615400ead8106a3309fb4e38b06f44753ca2b209aefe698aab5=60005460010160005500 7f4605a1aad677a8fb1dd57110051118add90d619b6dc53bd301e1849d40eeee=600160005401600055600060006000600073b0000000000000000000000000000000000000005af400 2cae8875430fe46523b61dc18a2fc87da9abeab97011c1ec7577fa7356ae0756=600160005401600055600060006000600073a0000000000000000000000000000000000000005af400 @@ -2068,67 +2068,67 @@ b0ad0eef9078a814b41980e9cd2dfeea6f102c1cdaa6aadb5fe563528cdd7254=600054600101600 1ec6f47a4fe34ebded91833b6aa3eface5f7c6f5bd6dbe8a4c413288ee2d3ac7=6000546001016000556000600060006000600073c00000000000000000000000000000000000000061c350f16001555a60025500 a35f8f16a1d016bdf12a2b6acce812fe1e5e8a77c0f4f22a387c645583422111=6000546001016000556000600060006000600073b000000000000000000000000000000000000000620249f0f16001556000600060006000600073d000000000000000000000000000000000000000620249f0f160025500 b729186ceaa5a67fd8098e83f30236febf44a9f5d91de570fe34bb3af857e73a=6008600255600060006000f050600c60035500 -b97fb21bf3656ee0f7c642b99c3650acda2cfcb26474a23e1fbaf07bab794939=60406000604060006103e873945304eb96065b2a98b57a48a06ae28d285a71b561c350f26000553d6001556020600060403e60405160025500 9dce4945c71d01792533bd9e5329578fc79e8445aeaec2f2ccf34b63a487e5c8=61223260005260206000fd00 +b97fb21bf3656ee0f7c642b99c3650acda2cfcb26474a23e1fbaf07bab794939=60406000604060006103e873945304eb96065b2a98b57a48a06ae28d285a71b561c350f26000553d6001556020600060403e60405160025500 53a1824fc1a4451a418c68bbf4a08b9e1814e872d34c49af967d79e2454f988f=3050600d80602460003960006000f0503d6000556020600060003e6000516001550000fe6211223360005260206000fd00 -70598f4acaa69f4a950ab8fd0b0d08717e7c220f057cd2507389ee6c24965617=604060006040600073945304eb96065b2a98b57a48a06ae28d285a71b561c350f46000553d60015560206000603f3e603f5160025500 df2ae27db7df40d08a468158826304dacf484d12bca37d68e1e214ff8e526e12=600a60205260206020fd00 +70598f4acaa69f4a950ab8fd0b0d08717e7c220f057cd2507389ee6c24965617=604060006040600073945304eb96065b2a98b57a48a06ae28d285a71b561c350f46000553d60015560206000603f3e603f5160025500 cc05c22789c7358145e0a5f77b240bf8e4ec982f93c5b6ae50984477a5b337dd=604060006040600073945304eb96065b2a98b57a48a06ae28d285a71b561c350fa60005500 af5d00491b061867822572fb3545c4061853a8d8e9c8a3ced43a51f5c34d0adf=60006000fd00 -319cd5ed40e8ff86432b4cf3316d74e2cbc0f6977b097135d447c3f4d064e448=6000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f1600455600e60055500 +3464e9bde5c71c833cc6831cd82721320f00e40234f90372a592d80882be119a=6000600060006000600073b3305374fce5edbc8e2a8697c15331677e6ebf0b620186a0f1600055600e60025500 +33d45503472dd1a4e113cc68e971b6caf3937fa02d770be80668055e68a5b527=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f4600055600e60025500 895860136351eed3de541eb3d09df83e8daa38b5fcc40c45269a6b4cab883ff8=600c60015560016000fd600d60035500 89e9a89b21328e3aea83e007869a6a4c3ff1b98fe94c60b1b07977d6c2f8b147=6000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f1600055600e60025500 -3464e9bde5c71c833cc6831cd82721320f00e40234f90372a592d80882be119a=6000600060006000600073b3305374fce5edbc8e2a8697c15331677e6ebf0b620186a0f1600055600e60025500 +319cd5ed40e8ff86432b4cf3316d74e2cbc0f6977b097135d447c3f4d064e448=6000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f1600455600e60055500 3b357612db25ba26854d2f37558c7a6a47f0a1dca4f46e16e5eeda523ff4e2e9=6000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f2600055600e60025500 7d1fdfa405f46c1e83d1ab1cd7b53f0a3cc0146c6c365c908d62690200d3cf54=600060006000600060006000356203f7a0f1600a5500 -33d45503472dd1a4e113cc68e971b6caf3937fa02d770be80668055e68a5b527=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f4600055600e60025500 14fbe20c970af8fc8c386203907c949991b93320df402bb9ed5185b88dc38a02=6e600160005560016000fd6011600155600052600f60116001f0600155600c60005500 8b1ce28462104780a7aa93982e97da1b6f6948d48b21e5bd48899717b0247f24=6000600060006000600060003561ea60f1600a5500 -20f7607c5fdd32c0f2095adc899402f5d758147244b93039be132d2d605f71cc=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073b3305374fce5edbc8e2a8697c15331677e6ebf0b620186a0f16000553d60025500 +d1b9a99ff301b3984b9a681af8a9abf44430b7837f840fb2b81e1e30381c4c2d=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f150600060006000600060006000356203f7a0f1600a5500 237fb00cc56bddf56cfe500979f1ced0efab82c327f8cd902800a197e0873324=600c60015260406000f300 +20f7607c5fdd32c0f2095adc899402f5d758147244b93039be132d2d605f71cc=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073b3305374fce5edbc8e2a8697c15331677e6ebf0b620186a0f16000553d60025500 2fc56ae367a9085b4961e02cb1a78061d320ea2601b907afdf2875fd8f902174=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f16004553d60055500 -dc66b56cd9184d970249516b0e5524c708b2e30be4563d17a5dc9a55e86800be=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f26000553d60025500 -d1b9a99ff301b3984b9a681af8a9abf44430b7837f840fb2b81e1e30381c4c2d=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f150600060006000600060006000356203f7a0f1600a5500 -eea250b53d6627f5ac656c0f6a5fcdc007795364ba913641335a4fba72d16423=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f16000553d60025500 6d3eeb967abb524f7487139cbd322889a1497f39d61b3631b9ac2415e7300b9f=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f150600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f46000553d60025500 +eea250b53d6627f5ac656c0f6a5fcdc007795364ba913641335a4fba72d16423=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f16000553d60025500 +dc66b56cd9184d970249516b0e5524c708b2e30be4563d17a5dc9a55e86800be=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f26000553d60025500 c80af6033aafda8dab0312529df7ac0e6ce3ee9e68664aa1f3d8714814f4ec3a=600d80601560003960006000f0503d6000550000fe6211223360005260206000fd00 -76e98a46d06ac4c527b7911bf149cc00716d8f28c9020bd2558a0cec9db9171f=6000600060006000600073b00000000000000000000000000000000000000061c350f2600a556000600060006000600073c00000000000000000000000000000000000000061c350f2600b556000600060006000600073d00000000000000000000000000000000000000061c350f2600c55600c600455600c60055500 -8cd7a6423ab8ec8845afd56fbcdcc2719343ae93b044567b2874c9e6918bbf37=6000600060006000600073b00000000000000000000000000000000000000061c350f1600a556000600060006000600073c00000000000000000000000000000000000000061c350f1600b556000600060006000600073d00000000000000000000000000000000000000061c350f1600c55600c600455600c60055500 ee8b9e96deaca789fef2e186e903ab4eca54f3779f9fcaa96dd9dd4a20eb34f0=6000600060006000600073b00000000000000000000000000000000000000061c350f1600a55600060006000600073c00000000000000000000000000000000000000061c350f4600b556000600060006000600073d00000000000000000000000000000000000000061c350f2600c55600c600455600c60055500 -ae83baa314f8d08ef26978bb651f062053846078ae2bea5838418e5a1842b23c=600c60025560016000fd00 -bb34e89b4f88309b086ec2581cd2eecc885fb51307e8543b002ce411c11d8594=600060006000600073b00000000000000000000000000000000000000061c350f4600a55600060006000600073c00000000000000000000000000000000000000061c350f4600b55600060006000600073d00000000000000000000000000000000000000061c350f4600c55600c600455600c60055500 +47a14c35cc677428f8a0ecd275553c312b4a296ce0f29475f5e0797a7d8fe2bf=600c60015560016000fd00 +8cd7a6423ab8ec8845afd56fbcdcc2719343ae93b044567b2874c9e6918bbf37=6000600060006000600073b00000000000000000000000000000000000000061c350f1600a556000600060006000600073c00000000000000000000000000000000000000061c350f1600b556000600060006000600073d00000000000000000000000000000000000000061c350f1600c55600c600455600c60055500 2698e2391cb7be2d6df86ba0062ad67d31b592d61362d8a5ac6107823316a283=6000600060006000346000356203f7a0f100 +bb34e89b4f88309b086ec2581cd2eecc885fb51307e8543b002ce411c11d8594=600060006000600073b00000000000000000000000000000000000000061c350f4600a55600060006000600073c00000000000000000000000000000000000000061c350f4600b55600060006000600073d00000000000000000000000000000000000000061c350f4600c55600c600455600c60055500 +ae83baa314f8d08ef26978bb651f062053846078ae2bea5838418e5a1842b23c=600c60025560016000fd00 04e48245db9a3c3476fed2e5d68e0db8f8492e5e5890e0624d72ea2aa2197762=600c60035560016000fd00 -47a14c35cc677428f8a0ecd275553c312b4a296ce0f29475f5e0797a7d8fe2bf=600c60015560016000fd00 -dd3283c605d58dbe21d0a0f2ab884dda1c6e149eaff1840a77e1e12d06103b53=6c726576657274656420646174616000556d726576657274206d65737361676560005260006001fd00 -d7257879609c29a12ae74b59a3fde006207a36328ff7f4fd2717eeba469dee1a=6c726576657274656420646174616000556d726576657274206d65737361676560005260206000fd00 -e2e3bbd0bda8f67f70369cb7206b24e0496d947130a64ca55e9130999e762309=6c726576657274656420646174616000556d726576657274206d6573736167656000526000610100fd00 +76e98a46d06ac4c527b7911bf149cc00716d8f28c9020bd2558a0cec9db9171f=6000600060006000600073b00000000000000000000000000000000000000061c350f2600a556000600060006000600073c00000000000000000000000000000000000000061c350f2600b556000600060006000600073d00000000000000000000000000000000000000061c350f2600c55600c600455600c60055500 +05b81dc0e5b0bd4187605683d6395f4d82d71703093e70dbdd3bc0fe0533710f=6c726576657274656420646174616000556d726576657274206d6573736167656000526e0fffffffffffffffffffffffffffff6000fd00 7181d3ffeaa870b0caf01a52a66ed7cd21ba2ee2b2045c33b011986fdd31ea5c=60206000600060006000600035620249f0f160015560005160025500 -459bee294ee0354c254d9b1732de0e598a4c560582d2773a239cd0f3fc66cacc=6c726576657274656420646174616000556d726576657274206d65737361676560005260006000fd00 +e2e3bbd0bda8f67f70369cb7206b24e0496d947130a64ca55e9130999e762309=6c726576657274656420646174616000556d726576657274206d6573736167656000526000610100fd00 +d7257879609c29a12ae74b59a3fde006207a36328ff7f4fd2717eeba469dee1a=6c726576657274656420646174616000556d726576657274206d65737361676560005260206000fd00 +dd3283c605d58dbe21d0a0f2ab884dda1c6e149eaff1840a77e1e12d06103b53=6c726576657274656420646174616000556d726576657274206d65737361676560005260006001fd00 558e0faf375d92de9928c588cbcc3df3292a09b6dd0378a8112952bbe580bbe2=6c726576657274656420646174616000556d726576657274206d65737361676560005260006e0ffffffffffffffffffffffffffffffd00 -05b81dc0e5b0bd4187605683d6395f4d82d71703093e70dbdd3bc0fe0533710f=6c726576657274656420646174616000556d726576657274206d6573736167656000526e0fffffffffffffffffffffffffffff6000fd00 +459bee294ee0354c254d9b1732de0e598a4c560582d2773a239cd0f3fc66cacc=6c726576657274656420646174616000556d726576657274206d65737361676560005260006000fd00 e5dd5859cf6cdb87486d7e024f31392ce9af7d4f24e935880b6a135151acac9a=60006000600060006000365af200 e4590715e0237590775cab8ca93ac7d8497f5441f19a05e3e9e38a3a5af9fcba=6000600060006000365af400 6b19b36fcd8315974e4f487b2fe71f3e75cfc690d5721b280c6f483d5fc07d78=60006000602035600060006000355af200 be94973c2c562d44b647c3bf84e2475f1ef7d0d19cd7f88973637552e788cb2b=60006000600060006000365af100 29d48283cedda1215773a86d298557f0f069d6265fd64e4171610c655a6614cb=6000600060006000365afa00 +e9a282e75cfff1a6ac9e90ceedd6af19f59d0424430b266601a5a9fda6673736=6000600060006000600161c350fa506000600060006000600261c350fa506000600060006000600361c350fa506000600060006000600461c350fa506000600060006000600561c350fa506000600060006000600661c350fa506000600060006000600761c350fa506000600060006000600861c350fa505a6001555a6002555a60035500 02fe24861294db45cf790d2433acdf09424d0063d527734767f7ececdcce2095=600060006000600060006000355af200 -2d6381d4b64e7fb761a5749f70108e4a6bd5fdfedbc665a2b63dcb5a1e419d8a=60006000600060006000600161c350f25060006000600060006000600261c350f25060006000600060006000600361c350f25060006000600060006000600461c350f25060006000600060006000600561c350f25060006000600060006000600661c350f25060006000600060006000600761c350f25060006000600060006000600861c350f2505a6001555a6002555a60035500 df05ce605786cf1f172027621ec602aa57b0b59011a8e363d786553b38845555=6000600060006000600161c350f4506000600060006000600261c350f4506000600060006000600361c350f4506000600060006000600461c350f4506000600060006000600561c350f4506000600060006000600661c350f4506000600060006000600761c350f4506000600060006000600861c350f4505a6001555a6002555a60035500 -e9a282e75cfff1a6ac9e90ceedd6af19f59d0424430b266601a5a9fda6673736=6000600060006000600161c350fa506000600060006000600261c350fa506000600060006000600361c350fa506000600060006000600461c350fa506000600060006000600561c350fa506000600060006000600661c350fa506000600060006000600761c350fa506000600060006000600861c350fa505a6001555a6002555a60035500 +2d6381d4b64e7fb761a5749f70108e4a6bd5fdfedbc665a2b63dcb5a1e419d8a=60006000600060006000600161c350f25060006000600060006000600261c350f25060006000600060006000600361c350f25060006000600060006000600461c350f25060006000600060006000600561c350f25060006000600060006000600661c350f25060006000600060006000600761c350f25060006000600060006000600861c350f2505a6001555a6002555a60035500 de7f48a9698a7a949a5cba3dbcc46058a43402095d34a5fa5db5d6a2cd6c5459=60006000600060006000600161c350f15060006000600060006000600261c350f15060006000600060006000600361c350f15060006000600060006000600461c350f15060006000600060006000600561c350f15060006000600060006000600661c350f15060006000600060006000600761c350f15060006000600060006000600861c350f1505a6001555a6002555a60035500 ee12ccf48321392c3161569794e59e70f7be0a94df08c8ad4745a1c22e177e45=60206000602060006000737db299e0885c85039f56fa504a13dd8ce8a56aa761c350f1600055600c60015500 e10e9441043a020bebab4dad741bbff857fd56514ba85587ced83a1cbbd8881f=60206000602060006000737db299e0885c85039f56fa504a13dd8ce8a56aa761c350f1600055600c600155600c60025500 c5c83e7953c7f26673d31c14507cc529cfeeb8cdc96d2cc7e770a7c22c6b1ea5=602060006000f0600055600c60015500 335c9e5c64580590e20b011cadb3ec940b6480733d2dbcafb664d956e9d6f41b=602060006000f0600055622fffff60002000 a918da4c499f558eae39cf8cb1054c391a9b036b7dcad9cf8a5bbcff148b7866=602060006000f0600055600c60015500 -5d8a411ccd418a3581405e3635df63eaa615b4018ed5e240a967ae5864ee9cbb=600060006000600060007310000000000000000000000000000000000000006201fbd0f1600255622fffff60002000 b2fd212493f89d3b09afd9c45eeabdae28600767536d39cc971048a8f451a456=600060006000600060007310000000000000000000000000000000000000006201fbd0f16000556000600060006000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0f160015500 -36b0a23503550cb1130badb6429992339e51df072f544b616c691ec951df4a49=6000600060006000600073d94f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0f16000556000600060006000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0f160015500 +5d8a411ccd418a3581405e3635df63eaa615b4018ed5e240a967ae5864ee9cbb=600060006000600060007310000000000000000000000000000000000000006201fbd0f1600255622fffff60002000 64820d3e7cc7fc1bea5d63ae7615070a7646ae1a0daf9a88650ff0a8635a1912=731000000000000000000000000000000000000000ff00 +36b0a23503550cb1130badb6429992339e51df072f544b616c691ec951df4a49=6000600060006000600073d94f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0f16000556000600060006000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0f160015500 739204052436f7bd0bd121ebc5bcf6270ffd6b7c5e533f1688fd7f2d59ab3351=6000600060006000600073e94f5374fce5edbc8e2a8697c15331677e6ebf0b620186a0f1600255622fffff60002000 -03cf95fee543c360abf34345f9e03afb9142224d593f7b2fbe8c2987a2514100=60006000600060006000731000000000000000000000000000000000000000617530f160015500 076fe75197c119cb43e28a5d7a04d7125e0213a96268b62cd1f857c6f493c69e=6000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b617530f1600055600160025500 +03cf95fee543c360abf34345f9e03afb9142224d593f7b2fbe8c2987a2514100=60006000600060006000731000000000000000000000000000000000000000617530f160015500 62516506325d7cd9a9c5ed8d0c534e9dde66627892fcb141a0a58814482c4d9e=60106000fd00 52aadc0ad8118342fb956b517e52d1e9af1705ebde4526e70a7e7803d994b5f7=5b6001156013576301000000600020506000565b00 7ff408e57e6ca4efed1ae0920cf2e2d4d01b9b11790d80fbb03e6a706145260e=600160000360002000 @@ -2143,7 +2143,7 @@ b4c5e7abf2c1e7d3ab977f12b44b93ae99ea6b4ce5c670a962d342aa6028203c=600060015560016 438fe345117cd7ad596753bcf57091f81c32dfca164e1b45269b97cf9c09e879=6000600b80601360003960006000f5500000fe6000600155600160015500 3bf29bf3eb0c4135fa025457b168546cb4980523dd9f0aa748f7d95c092e034b=6000600b80601860003960006000f55060006000fd0000fe6000600155600160015500 8fecce8e335fb1fb2a6807744153cbeee93c36edfeb191e66e4c005beda348aa=6000600b80603860003960006000f5506000600060006000600073dea000000000000000000000000000000000000062030d40f1500000fe6000600155600160015500 -3f0007b88f06463a813b03c55b07ee91057e2bc54fc36d4dac83a7a9e1a7afd7=611000600d6000805a915061beef6000555a9050828183030384556001840193505a915063deadbeef6000555a9050828183030384556001840193505a9150600080555a9050828183030384556001840193505a9150600080555a9050828183030384556001840193505a91506112346000555a9050828183030384556001840193505a915060006001555a9050828183030384556001840193505a91506160a76002555a9050828183030384556001840193505a915060006003555a9050828183030384556001840193505a91506160a76003555a9050828183030384556001840193506000805560006001556000600255600060035550505050 +3f0007b88f06463a813b03c55b07ee91057e2bc54fc36d4dac83a7a9e1a7afd7=611000600d600060005a915061beef6000555a9050828183030384556001840193505a915063deadbeef6000555a9050828183030384556001840193505a915060006000555a9050828183030384556001840193505a915060006000555a9050828183030384556001840193505a91506112346000555a9050828183030384556001840193505a915060006001555a9050828183030384556001840193505a91506160a76002555a9050828183030384556001840193505a915060006003555a9050828183030384556001840193505a91506160a76003555a905082818303038455600184019350600060005560006001556000600255600060035550505050 36f9db2473727c60d9e532538f556fe6bededa1527ed06644f1b093c8d37557c=600060015500 71891782a36768b68f09d49991e9e9b72f8555e2be3ce293dd936cb9bc1b33da=6000600060006000600073b000000000000000000000000000000000000000620493e0f1506000600060006000600073dea0000000000000000000000000000000000000620927c0f100 e099d68aa4f2daf6478c3bc0b7548c9734e931aadbb11b30f05e237e99d75350=6000600060006000600073b000000000000000000000000000000000000000620493e0f2506000600060006000600073dea0000000000000000000000000000000000000620927c0f100 @@ -2230,11 +2230,11 @@ e798273f90ee37816ec2050556e4ccb681c0a17dbe4ff09abf7ba18e33f8459b=600160015560006 2deb9469ef0902c49112f3d39d76c543221f25edf34221b99bf612720ce063ef=6001600155600060006000600073b000000000000000000000000000000000000000610903f415604e576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 8bbed1d29403ad31bc446e9eca24e6c2fedb931f1bd387377e80b179e966ffa6=476000526000516040526021603ff3 eb957dab28ae072ae7dcc6ed70eae55227971d7f99851ccc1be18704448a5361=4760005260206000f3 -8d95f8713c7ef660d149c2330a4ea05923319e1fad7a6acbc1804cb953f0dfbe=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101645760f281146101785760f4811461018c5760fa811461019f5761f1f181146101b25761f2f181146101c85761f4f181146101de5761faf181146101f35761f1f281146102085761f2f2811461021e5761f4f281146102345761faf281146102495761f1f4811461025e5761f2f481146102745761f4f4811461028a5761faf4811461029f5761f1fa81146102b45761f2fa81146102ca5761f4fa81146102e05761fafa81146102f55760fd811461030a5760fe81146103415760ff811461037a5760f081146103b25760f581146103d55761f0f181146103fb5761f5f181146104255761f0f281146104525761f5f281146104755761f0f4811461049b5761f5f481146104bd5761f0fa81146104e25761f5fa811461050b576460baccfa5781146105375765bad0bad0bad0600052610551565b47600052610551565b602060008060008061ca115af19550610551565b602060008060008061ca115af29550610551565b6020600080600061ca115af49550610551565b6020600080600061ca115afa9550610551565b602060008060008063ca1100f15af19550610551565b602060008060008063ca1100f15af29550610551565b6020600080600063ca1100f15af49550610551565b6020600080600063ca1100f15afa9550610551565b602060008060008063ca1100f25af19550610551565b602060008060008063ca1100f25af29550610551565b6020600080600063ca1100f25af49550610551565b6020600080600063ca1100f25afa9550610551565b602060008060008063ca1100f45af19550610551565b602060008060008063ca1100f45af29550610551565b6020600080600063ca1100f45af49550610551565b6020600080600063ca1100f45afa9550610551565b602060008060008063ca1100fa5af19550610551565b602060008060008063ca1100fa5af29550610551565b6020600080600063ca1100fa5af49550610551565b6020600080600063ca1100fa5afa9550610551565b4760005260005160005560008060008060006260bacc5af150476000526000516000541461033c57640badbadbad6000525b610551565b476000526000516000556000806000806000620600066161a8f150476000526000516000541461037557640badbadbad6000525b610551565b47600052600051600055600080600080600063deaddead5af15047600052600051600054146103ad57640badbadbad6000525b610551565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c610551565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c610551565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af19550610551565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af19550610551565b8160008563c0dec0de3c81846000f094506020600080600080895af29550610551565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af29550610551565b8160008563c0dec0de3c81846000f0945060206000806000885af49550610551565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af49550610551565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa9550610551565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa9550610551565b6103ff6000526020600060206000806460baccfa575af195505b508461055d5760206000fd5b836105685760206000fd5b600051600055505050505050 +8d95f8713c7ef660d149c2330a4ea05923319e1fad7a6acbc1804cb953f0dfbe=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101655760f2811461017b5760f481146101915760fa81146101a55761f1f181146101b95761f2f181146101d15761f4f181146101e95761faf181146101ff5761f1f281146102155761f2f2811461022d5761f4f281146102455761faf2811461025b5761f1f481146102715761f2f481146102895761f4f481146102a15761faf481146102b75761f1fa81146102cd5761f2fa81146102e55761f4fa81146102fd5761fafa81146103135760fd81146103295760fe81146103645760ff81146103a15760f081146103dd5760f581146104005761f0f181146104265761f5f181146104525761f0f281146104815761f5f281146104a65761f0f481146104ce5761f5f481146104f15761f0fa81146105175761f5fa8114610541576460baccfa57811461056e5765bad0bad0bad0600052610589565b47600052610589565b6020600060006000600061ca115af19550610589565b6020600060006000600061ca115af29550610589565b602060006000600061ca115af49550610589565b602060006000600061ca115afa9550610589565b6020600060006000600063ca1100f15af19550610589565b6020600060006000600063ca1100f15af29550610589565b602060006000600063ca1100f15af49550610589565b602060006000600063ca1100f15afa9550610589565b6020600060006000600063ca1100f25af19550610589565b6020600060006000600063ca1100f25af29550610589565b602060006000600063ca1100f25af49550610589565b602060006000600063ca1100f25afa9550610589565b6020600060006000600063ca1100f45af19550610589565b6020600060006000600063ca1100f45af29550610589565b602060006000600063ca1100f45af49550610589565b602060006000600063ca1100f45afa9550610589565b6020600060006000600063ca1100fa5af19550610589565b6020600060006000600063ca1100fa5af29550610589565b602060006000600063ca1100fa5af49550610589565b602060006000600063ca1100fa5afa9550610589565b47600052600051600055600060006000600060006260bacc5af1504760005260005160005414151561035f57640badbadbad6000525b610589565b4760005260005160005560006000600060006000620600066161a8f1504760005260005160005414151561039c57640badbadbad6000525b610589565b476000526000516000556000600060006000600063deaddead5af150476000526000516000541415156103d857640badbadbad6000525b610589565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c610589565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c610589565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af19550610589565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af19550610589565b8160008563c0dec0de3c81846000f0945060206000600060006000895af29550610589565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af29550610589565b8160008563c0dec0de3c81846000f094506020600060006000885af49550610589565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af49550610589565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa9550610589565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa9550610589565b6103ff600052602060006020600060006460baccfa575af195505b508415156105975760206000fd5b8315156105a45760206000fd5b600051600055505050505050 e072ca4e44f39e2861bf2dd3848ae1d57d606c88ab8fb7c557287f611fce8b15=4760005260206000f3 d230b310957a07eb653cf0f74a2f0b12b2ce777c388d2e7429a2f6f76863ee4c=47600052600051600055fe b0bbc0608478259d03d5b37781443defa85f60926523f33ac8621c634a3f8d8a=4760005260005160005560206000fd -dddc4cdd0ce51386ddc68be5f97ae1c4f9b0be4cf052c6024934cfae9fb271fc=600035600081036013574760005260206000f35b600181036000526020600060206000806460baccfa575af160345760206000fd5b60206000f3 +dddc4cdd0ce51386ddc68be5f97ae1c4f9b0be4cf052c6024934cfae9fb271fc=60003560008114156014574760005260206000f35b60018103600052602060006020600060006460baccfa575af1151560385760206000fd5b60206000f350 84f7e621ac63ff99a09b602712f898bc3267717a9a0cf5d3e0814ef96e5dad21=3031471460015500 ec8a200e05896c520c791fd009255daec79d60e47a4bece6d62c3881d8424812=4760015500 86ee8015bb2d147fad87d3214308454eb4ce9a5fec625543e74bfe62d82a3289=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001d60005500 @@ -2248,39 +2248,39 @@ ec181eee16d86db526290ad3b6fed53fc942d8879b0209cbc0239c9af57a3838=7b601080600c600 d5f3cccc5baa4f1489a77f9802821d3443fcb059dad76e3d3f1f29b3caa001a0=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206103e86080600060015afa60005560a060020a6103e851066001556001543214600255600060005260006020526000604052600060605260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060025afa6003556000516004556103e851600555600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060035afa6006556000516007556103e851600855600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060045afa6009556103e851601055600060005260006103e8526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a05260206103e860a1600060055afa6011556103e85160125560006000526000602052600060405260006060526000608052600060a05260006103e8527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d460605260406103e86080600060065afa6013556103e85160145561040851601555600060005260006020526000604052600060605260006103e8526000610408527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba602052600360405260406103e86060600060075afa6016556103e8516017556104085160185560006000526000602052600060405260006103e8526000610408527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206103e8610180600060085afa6019556103e85160205500 9587684c7d5328f4f12a5b051bd5d226074263879c6c11ae0bda0b52db7e4ef2=366000600037655a175a175a173660006000f560005500 5598916aa5224e161a88881cdcdf6d07e2660a4863e6a00ea4ab8bc257f3dcb0=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206103e860806000600162061a80fa60005560a060020a6103e851066001556001543214600255600060005260006020526000604052600060605260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060025afa6003556000516004556103e851600555600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060035afa6006556000516007556103e851600855600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060045afa6009556103e851601055600060005260006103e8526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a05260206103e860a1600060055afa6011556103e85160125560006000526000602052600060405260006060526000608052600060a05260006103e8527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d460605260406103e86080600060065afa6013556103e85160145561040851601555600060005260006020526000604052600060605260006103e8526000610408527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba602052600360405260406103e86060600060075afa6016556103e8516017556104085160185560006000526000602052600060405260006103e8526000610408527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206103e8610180600060085afa6019556103e85160205500 +cc45a5d135a8f9e57c309064b573fd2096be276abcca0a786f138b91173c9806=58600152600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d8761c350fa00 8d4ade0d727cfb64bfa4822027a066ce0356301bebb5a84a378d2d09d9592dd9=6000600060006000346000355af1600055600160015500 75b623adef17d8ee945396a0e457c02de9327d43bd6530247b01dbab9e6bccda=600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d8761c350fa600101585500 -5d48702bb1b7ab50547f4f7cb78d2dfbed39a5048e66ef3eeb7efab11b6a7616=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa585500 847517a05e83765f78c7a7f5f5c0ffd0f9aff3a2cdb0942a4c8e257546facffc=58600152600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa00 -cc45a5d135a8f9e57c309064b573fd2096be276abcca0a786f138b91173c9806=58600152600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d8761c350fa00 -7b0711df01faf8aa85459833a5f02dbfb532a3752b3effd24a93e9a9ca544a8f=600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa600101585200 +5d48702bb1b7ab50547f4f7cb78d2dfbed39a5048e66ef3eeb7efab11b6a7616=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa585500 6c08e575b788dedaa76e338d12c265b1e21bf330070c6ff3b2de4238e6216afc=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa585500 -de8e6310b88f5e61bb3e1cf61e5018deb5ce849331b8d66508b4d2e68aa6a874=58600152600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa00 e4affd2099ee1c5609d3fbae1291089a05099c54362e1641ce853fbe480ee806=600060006000600060006000355af1600055600160015500 +de8e6310b88f5e61bb3e1cf61e5018deb5ce849331b8d66508b4d2e68aa6a874=58600152600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa00 +7b0711df01faf8aa85459833a5f02dbfb532a3752b3effd24a93e9a9ca544a8f=600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa600101585200 3ae7d66fdc5bf050aae1b7a6aebd7b73f28a6f3a311c0d2c25ec3050c26f31c4=600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa600101585500 c574607dad90aee6b83c3fc1665a2aaf8128ef7b9e5b3e7961b9789b47aaccb4=6000600060006000346000355af1600055600160015500 -f29a742f9be9e76aa07187a36a8e607e1eff7939468a0c57c05e5611b58e5ad4=600160005401600055600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa00 -ffa82f8e8aca8c1b0edc26428ed39999b441647e0a65c7a518e874498b50d99c=600160005101600052600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa00 848ed1445089ed972a26f2115d5e8cff4e7f9c898926ee75e017f6da386f43b9=600160005101600052600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa00 +f29a742f9be9e76aa07187a36a8e607e1eff7939468a0c57c05e5611b58e5ad4=600160005401600055600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa00 03e0f6da45fc1ce6e52182732e8d12e56722585f37958a4ecd3510d452943ffd=600160005401600055600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa00 +ffa82f8e8aca8c1b0edc26428ed39999b441647e0a65c7a518e874498b50d99c=600160005101600052600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa00 69a88067624e01b6239912c9925d34b5f210adb5c8877b3a8aac27f36a23297b=600160005401600052600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa00 49ab705dc9bb9e656e931cf56281cab0fdc9aeb783237adc2d82105f0a1c1512=600160005401600052600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa00 -04c2ed31c0bae2704c6803bbc19baca5c9573d7d3c060e8ad5aba9e90011a916=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa585573945304eb96065b2a98b57a48a06ae28d285a71b5ff00 -ca714aeb6844ef9d58ffac2ee18ec087e8355e609476156b59aea4c14a19d112=600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa585273945304eb96065b2a98b57a48a06ae28d285a71b5ff00 a504bf49be3b2eb805df90688d764167d18e692ccac80bcb0740634b3321d26c=600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d8761c350fa600101585200 +ca714aeb6844ef9d58ffac2ee18ec087e8355e609476156b59aea4c14a19d112=600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa585273945304eb96065b2a98b57a48a06ae28d285a71b5ff00 +04c2ed31c0bae2704c6803bbc19baca5c9573d7d3c060e8ad5aba9e90011a916=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa585573945304eb96065b2a98b57a48a06ae28d285a71b5ff00 c82f5d265659d347880908fc2d570ab0b17bb8c30b9e9fde1f6ef665288704ec=600035600052600060006020600073095e7baea6a6c7c4c2dfeb977efac326af552d8761c35060003503fa50730f572e5295c57f15886f9b263e2f6d2d6c7b5ec6ff00 2de09a348bd19a028da60773913756f69431b621da433750cbb05afcb037b82b=600035600052600060006020600073945304eb96065b2a98b57a48a06ae28d285a71b5600035fa00 b9df2e03df2ca660f9df81aec2385169eb7445c609863aca34808497205337d6=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60fa600155600160645500 1e35ef69787f36587d5fb72e3def7ead221ea4af0bb297a02b427daee8f3184b=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60fa00 -0fa099c2413e5a9df168535bd5ce03c5e8cc96c6cda338fdc7ae58c4368967bd=600160015500 -9c1da38f1cea43836fcc7425513e0b01040c196afadfb4ff8da714f6dd5e1c89=600160015200 1559f73bf51a6bd64b56536e049892ddeaf090ff84d487076b145c18bd3450fe=5b61c3506080511015601c5760013b506001608051016080526000565b00 +0fa099c2413e5a9df168535bd5ce03c5e8cc96c6cda338fdc7ae58c4368967bd=600160015500 5b10e9929e41f007f2630f6e529ebc43513a2ec0779c11dc7cd2ebf790fe2717=6000600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b6064f100 +9c1da38f1cea43836fcc7425513e0b01040c196afadfb4ff8da714f6dd5e1c89=600160015200 8a9ea564d7839b7dfe036c25f7d6d498ef1b9efb6f370df0be73af42efc42a04=600160015200 fe1479307d0ae7d9c9a5a1f82259d21daad6a5de6f06319930318b8afd1f5736=5a600055602060006000f06001555a600255600060006000600060015461ea60fa6003555a60645500 9a25f942d2f6c17ef3b5de806a0557b10f8efc55a37fff018d937aa50cc20e05=5a6000557f600c6000556000600060006000600073c94f5374fce5edbc8e2a8697c15331676000527f7e6ebf0b61ea60f1000000000000000000000000000000000000000000000000602052604060006000f06001555a600255600060006000600060015461ea60fa6003555a60645500 -cedba9ece1b60951ead1283952052936b8b1d66a24bc5f802d2735729916a308=60016000540160005560006000600060005473bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffffa60015500 dd805dedda7c77cd5dc10c607c92bc756a9f0a638ed5a54244154f379d6e86fe=60016000510160005260006000600060005173cbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffffa60205200 +cedba9ece1b60951ead1283952052936b8b1d66a24bc5f802d2735729916a308=60016000540160005560006000600060005473bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffffa60015500 451dc2391994684f6b8b47a9cfc44c55a2eb0dd2f422239ece0a3ab09e22f733=600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b610401600054046001036127105a0302fa6001556103e86000540260010160025500 150da3077e45f07d5988f29883b09b41dce5e7ca9b1abe39b2b8d1478769ddef=600160005101600052600060006000600073cbbf5374fce5edbc8e2a8697c15331677e6ebf0b610401600051046001036127105a0302fa506103e86000510260010160205200 efee795e927f84fb0adb945f5fbc1ebac254360dcb44df54e75ee34087563cb6=600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa600255600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa600355600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff460015500 @@ -2296,12 +2296,12 @@ a4e0406c1baf1015f08c5ebb9eb902ecb905de40083d4fa9c04a675fac554b23=600160005101600 b65a639d937e5d2bf958c15440a67e4119682763bb358d0591d9da53a4716dd7=6000600060006000731000000000000000000000000000000000000103620927c0fa60095560006000600060006000731000000000000000000000000000000000000103620927c0f2600a5500 6a087fb788ade9003cb55a55d3910c758d4ab11e2c5d62a3de2f42618484f988=6000600060006000732000000000000000000000000000000000000103620927c0fa60095560006000600060006000731000000000000000000000000000000000000103620927c0f2600a5500 6ebaf83c33c2cee3af4f96f11416c73995ddfe353b7cfe9312ab7804eb3a7ed5=601260005200 -40feb2b16aa5295c8d81010e6dc7712ec8bcc1f3618a0d2bd4022dc5f17ecb3a=5a60085200 +d154d3443627ec7b9b4714482ec0c4912d141f67e1f21261a3eb342d2e115132=5a6008526000600060006000731000000000000000000000000000000000000108620927c0fa60095200 86e34fc9f92a233255712ea4dd5596532a0b00148b10f0c867dcc2c5e91450a3=6001600855600060006000600073200000000000000000000000000000000000010762030d40fa60095500 +75f0c2ebd23355bc89911c75994a8f86f2d9b49ad6e9bb73d4b538c03b1e4d5f=5a6008526000600060006000732000000000000000000000000000000000000108620927c0fa60095200 5068499c922fdc5490952a26514b9653928a238e05efa21438bd82bdc3115f45=600160085500 +40feb2b16aa5295c8d81010e6dc7712ec8bcc1f3618a0d2bd4022dc5f17ecb3a=5a60085200 b7c05ea76a53e47443a315cdebc8d471eb1d2a8a6b5a3457b81ffb67ec948b0b=6001600855600060006000600073100000000000000000000000000000000000010762030d40fa60095500 -75f0c2ebd23355bc89911c75994a8f86f2d9b49ad6e9bb73d4b538c03b1e4d5f=5a6008526000600060006000732000000000000000000000000000000000000108620927c0fa60095200 -d154d3443627ec7b9b4714482ec0c4912d141f67e1f21261a3eb342d2e115132=5a6008526000600060006000731000000000000000000000000000000000000108620927c0fa60095200 3df6ceea3eb0ac5fd7b62ad34dc5a845fbb94db7d6778225956b191fad1f0c07=74600c60005566602060406000f060205260076039f36000526015600b6001f060005560006000600060006000546000fa60015500 054829905933d02b982db54f2071b13c66774b1e1e01c7d9880333b9d8453873=74600c60005566602060406000f060205260076039f36000526015600b6001f060005560006000600060006000546000fa00 8cf4961ea0d0e182af73c824d25be9acfe545eb446befad5c4c92c18c1f24175=74600c60005566602060406000f060205260076039f36000526015600b6001f06000556000600060006000600054620249f0fa60015500 @@ -2322,9 +2322,9 @@ b608e2bd975152e4ef474640765aeb8509e0e67131bdd4d97b1f63c1813e10a0=7f1122334455667 c26fa0477659989e854da9505974ab47978b16cde9fa9e4d24bf9c0b46ea7f61=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527eb1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206080608060006001620493e0fa60025560a060020a60805106600055600054321460015500 15479cd180bb76cade7a0e123e5c9abf66feb718b97c77a879a49ab8615baf9c=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527eb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206080608060006001620493e0fa60025560a060020a60805106600055600054321460015500 ca5ef10e7d080d96e21e5d67bbb21cb2b3cdc5fde37a738066db40eb433cdaf4=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206080608060006001620493e0fa60025560a060020a60805106600055600054321460015500 +dd44572feb385d8fe9932d59c83716c9eeb9ca62fee1056eec4a07a3b75da4b6=5b61c3506080511015601c5760013b506001608051016080526000565b00 2c480595fa5a2e2c59360c5b3822ce08adaf3651539472b08663d8546ad1d1a5=5a6008526000600060006000600035620927c0fa60095200 6d80de9a558f53c7cfcf2752f199c7ea1e8299b4896baac95e50bb86d570a996=6000356000526000600060206000731000000000000000000000000000000000000113620927c0fa600055600160015500 -dd44572feb385d8fe9932d59c83716c9eeb9ca62fee1056eec4a07a3b75da4b6=5b61c3506080511015601c5760013b506001608051016080526000565b00 76789aacaf2dfca81d7141317b87b177e44d376e98c5404fe25723223a064cca=622fffff60002000 bc825613a7f1964902f53f3b26ffeb59ce6fe49afe42d1926ef34898ef1b8e40=6000600060006000731000000000000000000000000000000000000110620927c0fa6009555a600a5500 a121df53d4b2823b2745d4a3ace3494ec0bb7309aa7a4780ed6ce94151d66300=5a6008526000600060006000731000000000000000000000000000000000000111620927c0fa60095200 @@ -2336,23 +2336,23 @@ e6216f38afec9b8417189b8b8a1ba657bfa12c83e0b508ec599cec9879fea3ae=7ffffffffffffff 062c0d6a7b8390dbb68e02dd2961e7b50eb2b2cf78eb4829c7f04cf213f1b8be=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052602060006020600060046012fa60025560005160005500 a4032162c4796e1f1035c3324bb69c6ea0add9185870fcbccb38cf7ef7304226=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000620f424060006004610258fa60025560005160005500 0dad64f8e747061352994cc46b4fdfb0531ce0c2b48b3e4e290be4ed86defbb2=600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b620186a060005402600101fa6001556103e86000540260010160025500 -c40420a1ee6f77e82cb5c34fe4abdc52f2cc080aeef8498dff83a8ba71ead65c=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b56305f5e100fa600055600160015500 fc5bcaa60198a96b3424b97c04893bc61345fafbc102838cee9e8b8c5872c116=600160005101600052600060006000600030612af85a03fa00 +c40420a1ee6f77e82cb5c34fe4abdc52f2cc080aeef8498dff83a8ba71ead65c=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b56305f5e100fa600055600160015500 9542ab676d0c6ce7d0c6e9416e7c2a4dd96147323a2d681b22708bf78c506ab4=6000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d875af250600160015500 100cba8d8715246e03dc7d526243a7ad966c48a10f2c7d7ec7658c6915aa83cf=600160005401600052690fffffffffffffffffff610402600051040260025260006000690fffffffffffffffffff61040260005104026000306104005a03fa00 -58949b3211da91b07c9ad06d44d6495a4580cb346b34666d10082209e401e5fc=6000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d875af250600160015500 2058053e9a9efeae0b48503c903bc03234d323547b8b93ce24bf1f345711bb62=600160005101600052600060006000600030613a985a03fa00 +58949b3211da91b07c9ad06d44d6495a4580cb346b34666d10082209e401e5fc=6000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d875af250600160015500 b468b4b9f144d1073ef24255286e8cee8bde42ee4fe9c6f48b85085b75b73f90=6000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d875af2600055600160015500 2150529b7493f71d56e4819d9fb79f8db3cf440287e12eb6bc9fc6582f5e94c2=60016000540160005260006000600060003060e05a03fa00 43dcd231f392efde20b464e095660a55b5f11a9c7571ef3af56b508ea7228ba7=6000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03f2600055600160015500 -fa765eadc8a248a3d70cd0b9fdba76e1c2bd5295c50d3221ccc59ecf5a74ed63=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa600055600160015500 44cf7ed8d3657fc221e460d1b9887a932a77355a332f1258cde6343163272f37=5a60005260206000a06000600060006000306161a85a03fa00 -8fbc02cd413bdc3aa02d26b618a1dcec05a8653178ce330fa7052c937700ed5b=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000a06000600060006000306161a85a03fa00 +fa765eadc8a248a3d70cd0b9fdba76e1c2bd5295c50d3221ccc59ecf5a74ed63=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa600055600160015500 2c96f792bb792015a367fe3dea4d767cda7e299c30c5213f8895f0621406b391=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa600055600160015500 +8fbc02cd413bdc3aa02d26b618a1dcec05a8653178ce330fa7052c937700ed5b=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000a06000600060006000306161a85a03fa00 1a48f8ed328af49b6b4316cf8db1d7ebc81e40feae9043c165eb5a6f08f0652e=600060006000600073bad304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa50600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b56707fffffffffffffffa600055600160015500 798b7d5a2d0d014cae0bc7b241134c6210d3b9feca3b87b2974c23d8f62d998e=60016000510160005260006000600060003062036b005a03fa00 -6bf82608cb5dea39e3ce20548dbc0573605056106a3b0bdc1167a4bf0b08fa6a=600160005101600052600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b562036b005a03fa00 9b9396aa9e585e07978689dc8b62ec7c725eafd0e428171285819af84e45fd97=600060006000600073bad304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa50600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b56707fffffffffffffff4600055600160015500 +6bf82608cb5dea39e3ce20548dbc0573605056106a3b0bdc1167a4bf0b08fa6a=600160005101600052600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b562036b005a03fa00 487086a2f5d1e95f82d466c76f251420a060201051b91829529ff9c305d6bdff=60206000600060006003610258fa60025560005160005500 e87c24e32b6c2d97958b2783226a013846b06eca75fd9f4993b1a491dd1e1390=64f34578907f60055260206000602560006003611770fa60025560005160005500 1bf524364daa2d53448259bb5cec67741ac010f3cf578672ef9e562b03fa9187=64f34578907f60005260206000602560006003611770fa60025560005160005500 @@ -2373,45 +2373,45 @@ b5262b9f1c246c973d4f2c29992121fb22bd990c653f7c13181d67986be7a981=64f34578907f600 19494f63b9c3dfbefc0579c0f1fc986978c6368ee0a5260b4df29796b3463985=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600060406040600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa60005500 e0b4e92497c879e419bfb2b86d55db1049dcc392419f555d1913a19b8a77c763=6001601f6000600073945304eb96065b2a98b57a48a06ae28d285a71b56103e8fa60005560005160015500 3a33b2afaae785160d59cca8bdcf315370a57d68fe7d3b483a3f09569a3d71a1=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600260006040600073945304eb96065b2a98b57a48a06ae28d285a71b5611388fa60005560005160015500 -b81fbebd2baa32e081159c48938fa8cc62696329a332407a144f8f71b70ed53c=6001600152622fffff60002000 b2d091a3977fac39677c8ec072add00e29a503669ffd9782d00ea6dc92612069=60006000600060007320000000000000000000000000000000000000006064fa00 +b81fbebd2baa32e081159c48938fa8cc62696329a332407a144f8f71b70ed53c=6001600152622fffff60002000 +1d099e1a209c69de5aa5df2481c89515b6cc1b69231af9f2a8d3bae95c6d7f08=60006000526000600060006000600173a200000000000000000000000000000000000001620186a0f16000526001600152600160025200 cd4f4fb73990b39df91ad313fa43a22d3c76c4b2b9a2a255dac85ba115bcdd13=600060006000600073a500000000000000000000000000000000000001620186a0f46000526000516001146036576002600155603c565b60016001525b00 -6bc69fe9150c2f3cc4109f9748d5e806e632b281714fda813d393a3b49dfc841=6000600060006000600073a300000000000000000000000000000000000001620186a0f26000526000516001146038576002600155603e565b60016001525b00 -758d97983f44fb944608801da50b9831182861e1db77739e7cb93b38073b373b=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a100000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +82852f92116f941bace53a80171ff4aef2b70e7508bf0217ba729be9fb8c1dca=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373400000000000000000000000000000000000000114604b5760026001556051565b60016001525b30734000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600114608a5760026001556090565b60016001525b00 +f66e92c07dfed6754d35c1970a83714e4bc0afd4b2c3c6d2be2273793dd6bfa2=6000600060006000600173a400000000000000000000000000000000000001620186a0f26000526000516001146038576002600155603e565b60016001525b00 404f9eb6bf83d63eae9918edc8e3fa7b7d91d1c8c281162e3ebc4ff7fd7940fa=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373300000000000000000000000000000000000000114604b5760026001556051565b60016001525b30733000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -6598fac36b2144a976e4e961f38735b42d9cbf37304e678a061e8428a6355e5f=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000014604b5760026001556051565b60016001525b30735000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 7ee389ec41c907f420e15834c14231da97e433d1c2d9cf63edf55c68c65849d3=6000600060006000600035620186a0fa60015500 -1d099e1a209c69de5aa5df2481c89515b6cc1b69231af9f2a8d3bae95c6d7f08=60006000526000600060006000600173a200000000000000000000000000000000000001620186a0f16000526001600152600160025200 -333b6ab0b37d67d33f0d7f98cd5be36363440995b6c2867733ae35f8325bc711=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373200000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a200000000000000000000000000000000000001146074576002600155607a565b60016001525b34600114608a5760026001556090565b60016001525b00 +758d97983f44fb944608801da50b9831182861e1db77739e7cb93b38073b373b=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a100000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +6598fac36b2144a976e4e961f38735b42d9cbf37304e678a061e8428a6355e5f=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000014604b5760026001556051565b60016001525b30735000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +6bc69fe9150c2f3cc4109f9748d5e806e632b281714fda813d393a3b49dfc841=6000600060006000600073a300000000000000000000000000000000000001620186a0f26000526000516001146038576002600155603e565b60016001525b00 b4bae1f29814deb5b8ae318af163cef95fc3eb9406e5cf9cb5c05b2404092824=6000600060006000600073a100000000000000000000000000000000000001620186a0f16000526000516001146038576002600155603e565b60016001525b00 -82852f92116f941bace53a80171ff4aef2b70e7508bf0217ba729be9fb8c1dca=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373400000000000000000000000000000000000000114604b5760026001556051565b60016001525b30734000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600114608a5760026001556090565b60016001525b00 -f66e92c07dfed6754d35c1970a83714e4bc0afd4b2c3c6d2be2273793dd6bfa2=6000600060006000600173a400000000000000000000000000000000000001620186a0f26000526000516001146038576002600155603e565b60016001525b00 -3b84f25377a4292b9e4f7b1fbc695c55a0c90a25ef625a01d76461d936a4a1e2=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373b00000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a100000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -d6d980714c607a88cb51370f544420aefaf837fd5066c1260a06898ec3714989=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373500000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a500000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -fede4d962d1269c9642938e02ddb5cfec17e2699590faae4d4e71aee7d0009ce=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373300000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a300000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -893fdb92897484a363c0727c19c79f18ebbded0ae77bdf253e86049a9ff18c37=6000600060006000600035620186a0fa6000526000516001146024576002600155602a565b60016001525b00 -ea4a267b25f60eb4da367c26f8ccd520958d24e4094f4cbd1a2611b1abd625e4=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373400000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a400000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -3e76ea67b634ad55e3c5a485cf4ec19b8c31d252da94477e142b56e10bac0550=73a3000000000000000000000000000000000000016020526000600060406020600073b000000000000000000000000000000000000001620186a0f260005260005160011460505760026001556056565b60016001525b00 -dd9bbe198fa3c3f386b5fa54577aa2df29323f665ee5701c4fff0df49662225f=73a4000000000000000000000000000000000000016000526000600060206000600173b000000000000000000000000000000000000001620186a0f260005260005160011460505760026001556056565b60016001525b00 +333b6ab0b37d67d33f0d7f98cd5be36363440995b6c2867733ae35f8325bc711=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373200000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a200000000000000000000000000000000000001146074576002600155607a565b60016001525b34600114608a5760026001556090565b60016001525b00 d9099ee8b971d5cfff89f8f538c03a7dc0db58ac2c15eb282b3a490fb6ebab54=73a500000000000000000000000000000000000001600052600060006020600073b000000000000000000000000000000000000001620186a0f4600052600051600114604e5760026001556054565b60016001525b00 57b4bb4a6cdf644ff79a4f0616ec39a559001128c1f801d817854a3ad163a859=73a1000000000000000000000000000000000000016000526000600060206000600073b000000000000000000000000000000000000001620186a0f160005260005160011460505760026001556056565b60016001525b00 +dd9bbe198fa3c3f386b5fa54577aa2df29323f665ee5701c4fff0df49662225f=73a4000000000000000000000000000000000000016000526000600060206000600173b000000000000000000000000000000000000001620186a0f260005260005160011460505760026001556056565b60016001525b00 +d6d980714c607a88cb51370f544420aefaf837fd5066c1260a06898ec3714989=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373500000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a500000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +ea4a267b25f60eb4da367c26f8ccd520958d24e4094f4cbd1a2611b1abd625e4=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373400000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a400000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +893fdb92897484a363c0727c19c79f18ebbded0ae77bdf253e86049a9ff18c37=6000600060006000600035620186a0fa6000526000516001146024576002600155602a565b60016001525b00 fec8703d9ae566b4ed571b0841440a97b05c473c43f1f67cf70c6b8b8645e646=73a1000000000000000000000000000000000000016000526000600060206000600173b000000000000000000000000000000000000001620186a0f16000526001600152600160025200 +fede4d962d1269c9642938e02ddb5cfec17e2699590faae4d4e71aee7d0009ce=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373300000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a300000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +3e76ea67b634ad55e3c5a485cf4ec19b8c31d252da94477e142b56e10bac0550=73a3000000000000000000000000000000000000016020526000600060406020600073b000000000000000000000000000000000000001620186a0f260005260005160011460505760026001556056565b60016001525b00 +3b84f25377a4292b9e4f7b1fbc695c55a0c90a25ef625a01d76461d936a4a1e2=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373b00000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a100000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +a0a9ad09b174a0e4b69fd8e66e3538164ef7f66206e3e61ea165eb9404f75b5c=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000014604b5760026001556051565b60016001525b30731000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 adf9f5e900872addcd20976752fa8c397bd63527cd62e41ad2884f10e2e22de9=6000600060006000731000000000000000000000000000000000000001620186a0fa6001556000600060006000731000000000000000000000000000000000000002620186a0fa6002553360035534600455326005553060065500 98a8f573ecd230d28465b6ae3ec5958c28c7fd153e67a05c7277cd4ea862f628=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000014604b5760026001556051565b60016001525b30731000000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -a0a9ad09b174a0e4b69fd8e66e3538164ef7f66206e3e61ea165eb9404f75b5c=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000014604b5760026001556051565b60016001525b30731000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -4541ff509f4b7f945bfbb98bfc5c9a5d24b0ea229a33f66a2b8ff30a55ba1d36=73b0000000000000000000000000000000000000026000526000600060206000600a73a000000000000000000000000000000000000002620186a0f100 -87bc076915cabd26d946ac8ff1d7ef9f1490d8c3d912cf9baa9c74fe74992b45=73c500000000000000000000000000000000000002600052600060006020600073a000000000000000000000000000000000000002620186a0f400 e6833afb60bec0da2d810a52522e631d53e19fa2b77f83f5a8b06a2133185be3=600060006000600060006000356203d090f160015500 -c70e6cd29563926bb175ad7acebc55c469d5b5df8a99b82ad3df330ae8580133=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373400000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c400000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +87bc076915cabd26d946ac8ff1d7ef9f1490d8c3d912cf9baa9c74fe74992b45=73c500000000000000000000000000000000000002600052600060006020600073a000000000000000000000000000000000000002620186a0f400 +2e7f9ae3b2d4a46fc16e0a417b8562802fc3d41504ef2ac83c5fe3b88ae06175=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373300000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c300000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 fdc379e7a00f997a69a26b3e5111261b02b9a43dde5f67400e1244f288a45f63=73b0000000000000000000000000000000000000026000526000600060206000600073a000000000000000000000000000000000000002620186a0f100 5e9e34dec2ea7ebe341e51daa89b9da17cab841d1caa960179a0c6c282ffd6c8=73c3000000000000000000000000000000000000026000526000600060206000600073a000000000000000000000000000000000000002620186a0f200 -2e7f9ae3b2d4a46fc16e0a417b8562802fc3d41504ef2ac83c5fe3b88ae06175=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373300000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c300000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -5cb5e5a7280bc21b84bd72fd523c26b90bad35b2e8de1077a2d48eae4c13940e=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373500000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c500000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -e4de4eb0dac078a046039bbea1e5b917af7de4f852be503d9cd871d4b8ceea93=600060006000600060003561c350fa60005500 ca56f36ac47069406dbd2855d9d6f06d0cf047655c766ce2d20ab1fa3cfc7856=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373a00000000000000000000000000000000000000214604b5760026001556051565b60016001525b3073b000000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +c70e6cd29563926bb175ad7acebc55c469d5b5df8a99b82ad3df330ae8580133=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373400000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c400000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +e4de4eb0dac078a046039bbea1e5b917af7de4f852be503d9cd871d4b8ceea93=600060006000600060003561c350fa60005500 +5cb5e5a7280bc21b84bd72fd523c26b90bad35b2e8de1077a2d48eae4c13940e=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373500000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c500000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +4541ff509f4b7f945bfbb98bfc5c9a5d24b0ea229a33f66a2b8ff30a55ba1d36=73b0000000000000000000000000000000000000026000526000600060206000600a73a000000000000000000000000000000000000002620186a0f100 62ed67099b2a0a74b3c9a5c69708fd2e705ce40103205bdf48c02cc44ff795f4=73c4000000000000000000000000000000000000026000526000600060206000600173a000000000000000000000000000000000000002620186a0f200 -1f49a79208f808b39c987e3b9a37e06ea7e0037376dc3fe45b453f2f1b19f5f3=6000600060006000731000000000000000000000000000000000000003620186a0fa00 46cfad55e6cbc241c831a87943487a7f8d3ff08287d0728812eca0b8ad5e9622=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000214604b5760026001556051565b60016001525b30731000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +1f49a79208f808b39c987e3b9a37e06ea7e0037376dc3fe45b453f2f1b19f5f3=6000600060006000731000000000000000000000000000000000000003620186a0fa00 def5a1a160fb678f39f631f5ea5031be5d2f6a89f4e7acc87fdf8f647813076f=6000600060006000600035620927c0fa60015500 ef66cde67e17bb3af5f101543f93df462bfa5ec7d2f5b7d459d4b4f1e63d50c1=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b6161a8fa60015500 6d779126382ca62b73d591ad0230bda4701f11eb9b4e9c15aef8a9dc1e9fdcad=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b611388fa00 @@ -2420,102 +2420,102 @@ ef66cde67e17bb3af5f101543f93df462bfa5ec7d2f5b7d459d4b4f1e63d50c1=600060006000600 f0a42cef1d3367adecb417fddfe30066452b568dd64eed7a67a74cd80a2c451a=60006000600060006000731000000000000000000000000000000000000000620186a05a03f1600055600160015500 a0f6b36645b102ba27d6bb08d20028bc9e1a027b2889cbf272845f825aa0ac88=600060006000600073a0000000000000000000000000000000000000005afa00 55c56c0457696b45ea272ebaa736e6aa2d5a09f24adc2b3e731ee01896371c8a=600060006000600073b0000000000000000000000000000000000000005afa00 -318f3bc4238b8114f152600cf9fdc7bd6771f8f066a72d613c06071fa23cd7c1=60005160010160005200 c84ec6b401222601c68ccddf2f4cb0dc5daf3815e2cc85de439948e7f6ff979a=6103526000526000600060206000600073a0000000000000000000000000000000000000006127105a03f1600055600160015500 +318f3bc4238b8114f152600cf9fdc7bd6771f8f066a72d613c06071fa23cd7c1=60005160010160005200 6083b5f500257ccd1475297c47c0142c27992657c96be39c8518e78943d3f54b=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600060006040600073945304eb96065b2a98b57a48a06ae28d285a71b5617530fa60015560005160025500 639df5cf6341d6b4c631c0237f9bf4779e4fc65ce032bd73f2494793ea32708b=60006000600060007310000000000000000000000000000000000000016707fffffffffffffffa60015560006000600060007310000000000000000000000000000000000000026707fffffffffffffffa60025560006000600060007310000000000000000000000000000000000000036707fffffffffffffffa60035560006000600060007310000000000000000000000000000000000000046707fffffffffffffffa60045560006000600060007310000000000000000000000000000000000000056707fffffffffffffffa60055560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60065560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60075560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60085560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60095560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600a5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600b5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600c5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600d5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600e5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600f5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60105500 54e49fc3421fb9c8baa336e22373997544c2384a364621f58cb3f6293d0464ef=60006000600060007310000000000000000000000000000000000000016707fffffffffffffffa60015560006000600060007310000000000000000000000000000000000000026707fffffffffffffffa60025560006000600060007310000000000000000000000000000000000000036707fffffffffffffffa60035560006000600060007310000000000000000000000000000000000000046707fffffffffffffffa60045560006000600060007310000000000000000000000000000000000000056707fffffffffffffffa60055560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60065560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60075560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60085560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60095560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600a5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600b5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600c5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600d5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600e5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600f5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa6010556000600035146102af575a6102b7565b622fffff6000205b00 -7d62497b16e28a08693cef3aea82332aa0b1561781d889c69cf955622c557dde=600060006000600073094f5374fce5edbc8e2a8697c15331677e6ebf0b622dc6c0fa505a60015500 bda26e862bfee374bea68999f70d8e5842cc79afc545ddba0af90cb2a383258b=600060006000600073094f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0fa505a60015500 +7d62497b16e28a08693cef3aea82332aa0b1561781d889c69cf955622c557dde=600060006000600073094f5374fce5edbc8e2a8697c15331677e6ebf0b622dc6c0fa505a60015500 +097b9519ac8275905c177e3b6f7cc42b63bbaa224382603f1baa61db996b6d53=611f406000611f40600073094f5374fce5edbc8e2a8697c15331677e6ebf0b622dc6c0fa505a60015500 34676a20c227fbeb2467c2781ea554fb488bbe4c1b820cba1e9a12b99e6b6406=611f406000611f40600073094f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0fa505a60015500 037054064d2afc539fe9ed7ccb779971403d394ce2bcfbcbe999c5fbb09b5f96=5a60005200 -097b9519ac8275905c177e3b6f7cc42b63bbaa224382603f1baa61db996b6d53=611f406000611f40600073094f5374fce5edbc8e2a8697c15331677e6ebf0b622dc6c0fa505a60015500 2f32bfbb2e5247f725e01a4151857de7cabd85f8da8a135394402ac23f913774=6015600052602060206020600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b611b58fa5060005160005560205160015560406000f300 358f48d33170ae527eb2db1e7a59eaf9d5cca8797c10de562e117136502cf231=6001601f6001601e73b94f5374fce5edbc8e2a8697c15331677e6ebf0b6107d0fa506000516000556002601ef300 -f893caffc84199ad12a96155f4955dbc2c9fe5eed0fa06f9b42e3364eb38cf35=600054600101600055600060006000600073b000000000000000000000000000000000000000620249f0fa600155600060006000600073d000000000000000000000000000000000000000620249f0fa60025500 7a5df1bde40bb02b724eafff4243f6134e6e7d3526333fe9f8c1c85ea370818d=600060006000600073c00000000000000000000000000000000000000061c350fa50622fffff60002000 +f893caffc84199ad12a96155f4955dbc2c9fe5eed0fa06f9b42e3364eb38cf35=600054600101600055600060006000600073b000000000000000000000000000000000000000620249f0fa600155600060006000600073d000000000000000000000000000000000000000620249f0fa60025500 13c00864a3879ed5f8d801b044d0edb2db81ecb48eb35ea08961c8e18dd466ba=600060006000600073c00000000000000000000000000000000000000061c350fa50600160015200 50b35dca6e8923fb30f02c47e37dd62e6bdaeefc968557c43a54f742f72bddc3=60016000fd00 ce064fd2d509a2a0db6f14d867a25cdccf0d953da247155bb71531503b66a2e3=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350fa6000553d60015500 f3e5f529719929897d5d04c7b0cdbe69ec76bfe6aebba78cd50ccf82343e7308=5a600055600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60fa600155622fffff600020505a60645500 -6c9893edc37020e5544719f667e6d96a047f452a16abf2012732cc80e3b14692=73c94f5374fce5edbc8e2a8697c15331677e6ebf0bff00 fe3cc22b069757e210195ba7849dce069c1bc14d0f9ac7bc1536ae26d0d92ba0=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b620186a0fa50622fffff60002000 -f947f4791642e13dacac38aaf6f22eef10019f8b3d1f4181a4b77cae1d1ac35f=60006000600060006000732000000000000000000000000000000000000003619c40f150600160015200 +6c9893edc37020e5544719f667e6d96a047f452a16abf2012732cc80e3b14692=73c94f5374fce5edbc8e2a8697c15331677e6ebf0bff00 5474525e8a4ea3b05ca1910e3be360becdef41f627bb6f49e1843f55c899b3cf=600a6001a0600160015200 -6034354c9b6e85bc2acc17ebb92030ce865861ae2a27ac1d07844358c8f3966c=60006000600060006001733000000000000000000000000000000000000003619c40f250600160015200 8fede10b0db14fe3e0d42fecb434cd7a7d3ae283dbbb63e5d821961500107361=6000600060006000600035620186a0fa600055600160015500 7115c22971934f96b6570f7e3aa596bb52d623ffb9c43aff0907bfc83ae6fb20=600160015500 -1c0c7da972d6d49d681e09bbbcbbb1fc7dcab9c32316d8016a0337311aef6cf9=60006000600060006001731000000000000000000000000000000000000001620186a0f16000556000600060006000731000000000000000000000000000000000000001620186a0fa60015560006000600060006001731000000000000000000000000000000000000001620186a0f16002555b61c3506080511015608f5760013b506001608051016080526073565b00 -c10efa0cbca70244752be297ca37f60917710b83d4b1be7cd5d34735be272749=60006000600060006001731000000000000000000000000000000000000002620186a0f16000556000600060006000731000000000000000000000000000000000000002620186a0fa60015560006000600060006001731000000000000000000000000000000000000002620186a0f160025500 -f5219dd69682938778c67a55be416d2a8cb7ce6606c81f9f84b825e12596d207=600160015200 +6034354c9b6e85bc2acc17ebb92030ce865861ae2a27ac1d07844358c8f3966c=60006000600060006001733000000000000000000000000000000000000003619c40f250600160015200 +f947f4791642e13dacac38aaf6f22eef10019f8b3d1f4181a4b77cae1d1ac35f=60006000600060006000732000000000000000000000000000000000000003619c40f150600160015200 efcbe7cad146b3569f6f9ed022c67902de9346ebf2b9dbbf170169d1c8441535=6000600060006000600060003562055730f100 -81da54faf4b0963c7813553b36a4c6c47cae9d75126b211993e84f83f9156485=600160015260015460015500 20779731aefa455ec0d2a73e6dd65d49097e17935e96551f94116d28e20ffc25=60006000600060006001731000000000000000000000000000000000000001620186a0f16000556000600060006000731000000000000000000000000000000000000001620186a0fa60015560006000600060006001731000000000000000000000000000000000000001620186a0f160025500 -ad6840ba504c8dca4fd3c27940133e7f437ac30748b8ecc256f4817a43954267=600060006001f06000556000600060006000600054620493e0fa60015500 -2a3b69feb75aad4db6f3008ae9c18771ce6d868e5649242fd14db009847ce1d8=6d6460016001556000526005601bf3600052600e60126001f06000556000600060006000600054620493e0fa6001555b61c3506080511015604b5760013b50600160805101608052602f565b00 +f5219dd69682938778c67a55be416d2a8cb7ce6606c81f9f84b825e12596d207=600160015200 +c10efa0cbca70244752be297ca37f60917710b83d4b1be7cd5d34735be272749=60006000600060006001731000000000000000000000000000000000000002620186a0f16000556000600060006000731000000000000000000000000000000000000002620186a0fa60015560006000600060006001731000000000000000000000000000000000000002620186a0f160025500 +81da54faf4b0963c7813553b36a4c6c47cae9d75126b211993e84f83f9156485=600160015260015460015500 +1c0c7da972d6d49d681e09bbbcbbb1fc7dcab9c32316d8016a0337311aef6cf9=60006000600060006001731000000000000000000000000000000000000001620186a0f16000556000600060006000731000000000000000000000000000000000000001620186a0fa60015560006000600060006001731000000000000000000000000000000000000001620186a0f16002555b61c3506080511015608f5760013b506001608051016080526073565b00 f567658186b9fcfcc93374e8b6b6c3888747b8a676569d572b0f833ef1f79fd5=60006000600060006000600035620927c0f100 +ad6840ba504c8dca4fd3c27940133e7f437ac30748b8ecc256f4817a43954267=600060006001f06000556000600060006000600054620493e0fa60015500 184c22c4d3b69c05d98a7888a713a908bc8fa4a3c0524ed972798a1df246524d=6d6460016001556000526005601bf3600052600e60126001f06000556000600060006000600054620493e0fa60015500 +2a3b69feb75aad4db6f3008ae9c18771ce6d868e5649242fd14db009847ce1d8=6d6460016001556000526005601bf3600052600e60126001f06000556000600060006000600054620493e0fa6001555b61c3506080511015604b5760013b50600160805101608052602f565b00 c162de6a05cb28543af03d0fdcdbd4afaa8dc91627e8d951d30890f03c08b28f=766d600060006000600030620186a0fa600052600e6012f3600052601760096001f06000556000600060006000600054617530fa600155600160025500 -9c5629db4116e8b9ee4529087d3132274afd004cb5d6a9c975e696785820c364=6000600060006000731000000000000000000000000000000000000002620249f0fa00 bab3a4ca0f0d3f77feea2d4793233f045bf315fe47f579fee2d2dd241ce192a6=600160016000f000 024a0cb9c27cdf47846d83d334c827a21d20974fe1c1cbbcc62f739bb0a07b60=6000600060006000600035620493e0fa60005500 dece64523169799927485282e2fb02181ec6935ad838ddc51b11be52bd5101de=60006000600060006000731000000000000000000000000000000000000002620249f0f100 373127720fce833627b38d2114f193a8adeabb9d3228a1458399c665c67b8a82=6000600060006000731000000000000000000000000000000000000002620249f0f400 +9c5629db4116e8b9ee4529087d3132274afd004cb5d6a9c975e696785820c364=6000600060006000731000000000000000000000000000000000000002620249f0fa00 2f7920b36306229d530687f7eca3244cb65799eb14fcbafe7a6923e44212308e=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350fa5060005160005500 f56bfbe6b2842f1010a7139b0bacab690f400ac718429a8d12cde6c54e3b396b=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600060006020600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350fa5060005160005500 efc9308c2a34f83b2767bf47bdbd05a6867d7cae92e0ffc09862b842eec8e0a0=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052602060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350fa5060005160005500 0aa22eb4acc24219c0c94948b65c062352a4a77862c669dcadfd56efe48c54d7=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600a60006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350fa5060005160005500 +b06fe602262b042548fa44e76b9295acc2952d28206385c9e67347d1a89dd95f=6000600060006000600035620186a0fa60005500 4b0ed9836107b1329850e71c8c4996b671b6f519a521ba8e05457e55ad4fa6c3=60006000600060006000731000000000000000000000000000000000000002620186a0f26000526000516001146038576001600155603e565b60016001525b00 4fb0bde6147b7281a0ed0205b519c2c569f4280507f6e678747805ea9ac929bd=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000114604b5760026001556051565b60016001525b30731000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -b06fe602262b042548fa44e76b9295acc2952d28206385c9e67347d1a89dd95f=6000600060006000600035620186a0fa60005500 -802c7ddf3b32e2f65e55845250538d5e7502ede4769c36c0d55cc2f48eaf317a=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000114604b5760026001556051565b60016001525b30731000000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 e0a4ebf1aad3532ab57071d51cbac3950a28db80dfacef64d3f18b29e320e723=60006000600060006000731000000000000000000000000000000000000002620186a0f16000526000516001146038576001600155603e565b60016001525b00 +802c7ddf3b32e2f65e55845250538d5e7502ede4769c36c0d55cc2f48eaf317a=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000114604b5760026001556051565b60016001525b30731000000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 48f7bb89bf24e39f4e6a8fdde75e16afd9e340770e6ad10a7f50dc4e5653600e=6000600060006000731000000000000000000000000000000000000002620186a0f46000526000516001146036576001600155603c565b60016001525b00 4b09828843cc97f3ebe8366dd6d58b458d4db4ebbdf08a36a51fd91e3d8d626a=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000014604b5760026001556051565b60016001525b30731000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 bc8fbd8026656526c8a4c4740804bcbf30242133f1017f5a11c4adb16c196101=6000600060006000731000000000000000000000000000000000000002620186a0fa6000526000516001146036576001600155603c565b60016001525b00 +273b9c83b9e6837aacaaf9d5ab1a3435f2cd460d8d8b62e24294906cd77c64f8=600060006000600060006000356207a120f100 770a7da5d03a877e5569478a32fe9faa47dcff9cfea041326718e8beb8f2ae1a=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600260006040600073b45304eb96065b2a98b57a48a06ae28d285a71b56bfffffffffffffffffffffffffa60005560005160015500 3ef2444fa2b3daeb1a7d270d4ce04d5b1d80ce37437d04ff69fa0032b34d7f24=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600260006040600073945304eb96065b2a98b57a48a06ae28d285a71b56bfffffffffffffffffffffffffa60005560005160015500 -273b9c83b9e6837aacaaf9d5ab1a3435f2cd460d8d8b62e24294906cd77c64f8=600060006000600060006000356207a120f100 9645880325e712facf18c761a16f9a38c5ce47466da9e94ce97750c6637a057c=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5622dc6c1fa60005560005160015500 221710d943fb41ef7392a65dd3437e16e9eab8b9653406e4a4f46358c86b98ad=600260006040600073945304eb96065b2a98b57a48a06ae28d285a71b561c350fa600055600160015500 c62e60fc7991dacd07ddfd072a372ca4b4ae04834fcccf52407067f16496170d=6001600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5600afa0160005560005160015500 6b87c77e280a7e4b563480328921528b7f504aa7afa01b2aa44713a744b4fe7e=6040600060406000731000000000000000000000000000000000000001611770fa6000555a60015500 3e7813be56cd8272e377454000b6f36f93cf00b7143e47742bd22081ba0b0e3d=6040600060406000731000000000000000000000000000000000000001611770fa6000555a60015500 -c3d241b2d7d6df2e8a3bb5dafb4d8aef3b57ca7da39a22626598159f9a7cfc0e=3460005260206000f300 68db2808557a587eb39bf7032a6daeb8f16cffa68127a01739657a6e083463da=602060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350fa60005560005160015500 +c3d241b2d7d6df2e8a3bb5dafb4d8aef3b57ca7da39a22626598159f9a7cfc0e=3460005260206000f300 95676c7e03b016f7dc9709c8ab4c1a36f1d8f6aac6370a232dfd90965b932a72=6000600060006000600a73094f5374fce5edbc8e2a8697c15331677e6ebf0b620186a0f100 c825eb8fb8c7d5e7333ed863327b648155c9ba1604e96cd2331e542043147066=6001600052336020523460405230606052326080523660a0523860c0523a60e05200 -efd0f30d72ee28f69abbbede2fea8c18ee14287e120bf79298326b0755248753=60406000604060007320000000000000000000000000000000000000026203d090fa00 -b7ad6bdf4604f9b8b757bfe05fc4ba38e10467d7d42755f7dcecce6e9530d574=60406000604060007310000000000000000000000000000000000000026203d090fa00 0540bc699d4dd5b0fa3fdb6efd5b7ceefa1b6d3cce742aedb30ce5396e218694=604060006040600073200000000000000000000000000000000000000162055730fa60005500 c4b8deae984aa5efa988bad6491930ff406a7685f87e5a4480b49b10eda1d492=604060006040600073100000000000000000000000000000000000000162055730fa60005500 +b7ad6bdf4604f9b8b757bfe05fc4ba38e10467d7d42755f7dcecce6e9530d574=60406000604060007310000000000000000000000000000000000000026203d090fa00 +efd0f30d72ee28f69abbbede2fea8c18ee14287e120bf79298326b0755248753=60406000604060007320000000000000000000000000000000000000026203d090fa00 475445062a8cf19a64a93251f1496ddc035ddf1d3501085b598c29f711ddd65e=60016002526040600060406000732000000000000000000000000000000000000002614e34fa50600160205200 -bf76068be5cbdd2c3bc4457cdf2a51627b1611a16f0db15efab83799fec63dbd=5b61c3506080511015601c5760013b506001608051016080526000565b00 -0e24e02427a8e83c8536e59980af01ea90a99ee69a0e6e8e9c78595bf5069796=6040600060406000732000000000000000000000000000000000000001620249f0fa60005500 0d4950aaa1ad9b0da6182d02ccdd623c45ffeaf725f3f02c035ce9b07ad8ff3c=600160025260406000604060007310000000000000000000000000000000000000026201d4d4fa50600160205200 43027427ed708586ce8369748f012aee319639dbc13862ef35e6758474f4dfcc=6001600255600160025200 +bf76068be5cbdd2c3bc4457cdf2a51627b1611a16f0db15efab83799fec63dbd=5b61c3506080511015601c5760013b506001608051016080526000565b00 +0e24e02427a8e83c8536e59980af01ea90a99ee69a0e6e8e9c78595bf5069796=6040600060406000732000000000000000000000000000000000000001620249f0fa60005500 9b0917aa70e74b7a3fdee1ab3685a8f2bb3d67a2e22ef4e1ff7e6fb46cd1b9f1=60016002526040600060406000732000000000000000000000000000000000000002620186a0fa50600160205200 -89dd62dafb714bb10931b9cb0574f03473f13c6754485aa5dcee061fc35e4188=6040600060406000731000000000000000000000000000000000000001620249f0fa60005500 f9d01335d8b800beefecb45a651309be0032a55978e09d8885a3f8a73c05dcf3=60016002526040600060406000731000000000000000000000000000000000000002620186a0fa50600160205200 -0350d4c406bbfc1aad8dd7e25e859c0464b5310206cc0ad8ed407a1a4b1a4ebc=5b61c3506080511015601c5760013b506001608051016080526000565b00 55dec7cefedba450204c1fa7b3b8cd7f714986da078e4a7cfb258b75cdff51c6=60016002553460055500 +89dd62dafb714bb10931b9cb0574f03473f13c6754485aa5dcee061fc35e4188=6040600060406000731000000000000000000000000000000000000001620249f0fa60005500 +0350d4c406bbfc1aad8dd7e25e859c0464b5310206cc0ad8ed407a1a4b1a4ebc=5b61c3506080511015601c5760013b506001608051016080526000565b00 a3a22b67827c10d53c308beb9aa880b926a6e7b2be5dabffc019492549a2033a=60016002526040600060406000731000000000000000000000000000000000000002620186a0fa50600160205200 97f5b7335c421b410bfd81628a8aa34a518662cd4a9557511718c845bcb913a1=60016002526040600060406000732000000000000000000000000000000000000002620186a0fa50600160205200 -d417f5e802616309071f6240ecfb572fbac573a4a1302cb560a13ab9db54313f=6001602052604060006040600073100000000000000000000000000000000000000261c350fa50731000000000000000000000000000000000000000ff00 e1c54b74c6d6e9606beae5fa041264d84e877eaa3aacd60cf2248c2ebc635c4b=600160025200 -c4a016d328743cacfb9b5b56a32359bb310ca5eeba7ac2cf55a4c56e1d61f4ec=60016003526040600060406000732000000000000000000000000000000000000002620493e0fa50600160205200 -aa4ee1aba16e5ec7311ebafdb9a904ef0f85d6e03a988740aa8b6154a042e4b4=600160035200 +d417f5e802616309071f6240ecfb572fbac573a4a1302cb560a13ab9db54313f=6001602052604060006040600073100000000000000000000000000000000000000261c350fa50731000000000000000000000000000000000000000ff00 1c123276d0c78004ecc4b697fdca7a2f8471bba878a800d994589440648d6b02=6001600352604060006040600073100000000000000000000000000000000000000262061a80fa50600160205200 +c4a016d328743cacfb9b5b56a32359bb310ca5eeba7ac2cf55a4c56e1d61f4ec=60016003526040600060406000732000000000000000000000000000000000000002620493e0fa50600160205200 608b30da060f19e5fc9e5d61f053f9328419e69eb55e1e047ef5c794a46870ed=60406000604060007310000000000000000000000000000000000000016209eb10fa60005500 -d97da057751123f2962112c654c0ef960c9bb07824891565d269b23fca4b50d6=600160035260406000604060007320000000000000000000000000000000000000036203d090fa50600160205200 +aa4ee1aba16e5ec7311ebafdb9a904ef0f85d6e03a988740aa8b6154a042e4b4=600160035200 ebab6cfa1bd31444a856b975c84cecd01192b10d0ae549de5c5157421ced65f3=600160035260406000604060007310000000000000000000000000000000000000036203d090fa50600160205200 +d97da057751123f2962112c654c0ef960c9bb07824891565d269b23fca4b50d6=600160035260406000604060007320000000000000000000000000000000000000036203d090fa50600160205200 +666da63f5fd3ab6bd27a0b52c3ef64ca80ca09a7b19156ed8a98ccc39da63dc1=6040600060406000731000000000000000000000000000000000000001620927c0fa60005500 +c664866980e1fe34d66555a12a11c700443137875c513dae8560a35d7ce52451=60016003526040600060406000731000000000000000000000000000000000000002620493e0fa50600160205200 0da1e7c490f7ab109d2b4d4403422f7b69e872c06663fcc367152053a71bd546=60406000604060007310000000000000000000000000000000000000016207a120fa60005500 -32f981e49e2bf55449a299597dd2dd99a2f0f84b15b1a2ba150851330292f499=60016003526040600060406000732000000000000000000000000000000000000002620493e0fa50600160205200 +b849c540c6aba10657a3a41940664b59713131e1f77b94296cd06898d5a61082=6001600355600160035200 9939830cf46abeb56072966cb23bd36fa74c759cdb3d4e9927696fcf58d7c342=5b61c3506080511015601c5760013b506001608051016080526000565b00 -c664866980e1fe34d66555a12a11c700443137875c513dae8560a35d7ce52451=60016003526040600060406000731000000000000000000000000000000000000002620493e0fa50600160205200 +32f981e49e2bf55449a299597dd2dd99a2f0f84b15b1a2ba150851330292f499=60016003526040600060406000732000000000000000000000000000000000000002620493e0fa50600160205200 3adbf55988966011734f99fd354b5f5060d6ef2e26eaa536f7073f28f896e919=600160035260406000604060007320000000000000000000000000000000000000036201d4d4fa50600160205200 -b849c540c6aba10657a3a41940664b59713131e1f77b94296cd06898d5a61082=6001600355600160035200 -666da63f5fd3ab6bd27a0b52c3ef64ca80ca09a7b19156ed8a98ccc39da63dc1=6040600060406000731000000000000000000000000000000000000001620927c0fa60005500 897e2856814c86522ec62ec68aa3854bbb296e9f4344509ee40ef880d035a5d8=600160035260406000604060007310000000000000000000000000000000000000036201d4d4fa50600160205200 cf13fb5722b4a8985f42be5ed89f861c4a3a7062f99ea272cc8b9082cd69901d=6040600060406000731000000000000000000000000000000000000001620aae60fa6000556001606f5500 1b4f611b885a40174a01499c4b21aa8c1007f4f54a7d31225cc1a5b972507efa=600160035260406000604060007310000000000000000000000000000000000000026206ddd0fa505b61c350608051101560445760013b506001608051016080526028565b00 @@ -2524,156 +2524,156 @@ ad1ee4098d7c69488a4fd01896a5f80b174952b5441237a8530b8adb63683f70=600160035260406 ed71de6e2f3390d6c2d109755f0e145366ac1c9eadd322ec8175da3dd631a077=600160035260406000604060007310000000000000000000000000000000000000036201d4d4fa50600160205200 655c5f203b56cf8a6ceeeecd79aeeaf34123b11bad8304a394ae71f5435459b3=604060006040600073100000000000000000000000000000000000000162092856fa6000556001606f5500 186822b494b604d7c7c1057eb6b150e7c9eeada500f72204647ff8fd3bc941d6=604060006040600073100000000000000000000000000000000000000262061ad0fa00 -b83f615d1696590a7ec4f1eac553cf448d43aacb673bd8157b785fd7d96745e1=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060007310000000000000000000000000000000000000036201d4d4fa00 74a61aa710c4800f07a12eca87ae6bc0bf81c55f7dcfd2b74550728fdca64693=6040600060406000731000000000000000000000000000000000000001620927c0fa600055600160015500 -c7a09115226858fd260a49d16e4d014933a2dbb76991bc073444ae738ae2804c=600160035200 +b83f615d1696590a7ec4f1eac553cf448d43aacb673bd8157b785fd7d96745e1=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060007310000000000000000000000000000000000000036201d4d4fa00 e025a502fa40535c61169eb1f08b3af3178c5425ad2869fdfb1afbb6aa12d7d8=6040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 6888874442bc917f71d01f5f084db2c729e88e53b009416512b04b602a7964b8=60016003526040600060406000731000000000000000000000000000000000000002620186a0fa50600160205200 +c7a09115226858fd260a49d16e4d014933a2dbb76991bc073444ae738ae2804c=600160035200 ab014f21cbf2b3399565c003383739c0d065011cf33c294534c6760d98d40374=6001600352604060006040600073100000000000000000000000000000000000000361c350fa50731000000000000000000000000000000000000001ff00 -dc31386900fa73974feded44a0f16b4f7aa29e6dd2291eed72a741ccbcf968c1=731000000000000000000000000000000000000000ff604060006040600073100000000000000000000000000000000000000361c350fa00 4a6e960d19852283c7b72f20fa7b04a88b051d7a3a613063709e1140d3c0be3d=6040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 -915a92c2026d93de0dffa46b7f37c7003694e3daa65fa556f4c4547a51cd1d76=6001600152604060006040600073100000000000000000000000000000000000000163017d7840fa50600160025200 +dc31386900fa73974feded44a0f16b4f7aa29e6dd2291eed72a741ccbcf968c1=731000000000000000000000000000000000000000ff604060006040600073100000000000000000000000000000000000000361c350fa00 afd1db53c3f5b489497a200ff589aeb007d9979d0bfd33eead6ee0732c95e02b=60016003526040600060406000731000000000000000000000000000000000000002620f4240fa50600160045200 +915a92c2026d93de0dffa46b7f37c7003694e3daa65fa556f4c4547a51cd1d76=6001600152604060006040600073100000000000000000000000000000000000000163017d7840fa50600160025200 690ca0710fb92000f668d54aaf7784300930602b36dc94246ebacba4779bfd5b=600160055260406000604060007310000000000000000000000000000000000000016207a120fa50600160065200 +3974d5c71fb125a5353bd7c8c9b5ff93aa74a5a403969d8de6fef553ff4e3621=60016003526040600060406000731000000000000000000000000000000000000002620493e0fa50600160035200 34d8761a05f3b29aeed5ec35a59210bbd9e9f0c2682576ae4f8b6f17a48306b4=600160035260406000604060007320000000000000000000000000000000000000036203d090f450600160035200 +6938c921e3d5b48ac019c8d0ed785c8f64885bfa7717c8c7fca15a949ab56c55=60016003526040600060406000732000000000000000000000000000000000000002620493e0fa50600160035200 afc9088819610f696ff1c705d58e85123fa8c72d603a1dc1d4bd6e13a7a1f5ec=604060006040600073100000000000000000000000000000000000000162055730fa600055600160035200 f332cc951eee86dba59a8b9d2c93d96d40801c25c6068c3bb59fa3ee23d73126=600160035260406000604060007310000000000000000000000000000000000000036203d090f450600160035200 -6938c921e3d5b48ac019c8d0ed785c8f64885bfa7717c8c7fca15a949ab56c55=60016003526040600060406000732000000000000000000000000000000000000002620493e0fa50600160035200 -3974d5c71fb125a5353bd7c8c9b5ff93aa74a5a403969d8de6fef553ff4e3621=60016003526040600060406000731000000000000000000000000000000000000002620493e0fa50600160035200 -c44f8a8322b00c2fe45a25d8bc8e7f33d4634728f787647dd49d75d89a2ea020=6000600060006000346000355af1600055600160015500 e0d4cd5d2b6fc5d75301ed128b521e335217fcca93bb3e84dbe30e00911122e2=6040600060406000731000000000000000000000000000000000000002620493e0fa50600160035200 b1f105737da31e39a435ccaca14d45bf7e966acbc89eeb4764ae931a356d241f=631122334460015200 +c44f8a8322b00c2fe45a25d8bc8e7f33d4634728f787647dd49d75d89a2ea020=6000600060006000346000355af1600055600160015500 a31685be6bc50872842b673c12b8f715652d15ab4538b870ddf4115f18a3108a=6040600060406000732000000000000000000000000000000000000002620493e0fa50600160035200 e5c21c6a73892cae374036c87ccb93503567dbcf8c17767cd3824b7a43c50a71=6001600452604060006040600060007320000000000000000000000000000000000000036203d090f250600160065200 -28259b787a771ce6a0442343dd8508b2f94ae391ba33b12365bbc17035c31e86=600160035260406000604060007310000000000000000000000000000000000000036201d4d4f450600160035200 44eeb1e90b4ba9f1cac8c855b777bcb4509d5d53263e3169665463b112fd41d8=6040600060406000731000000000000000000000000000000000000001620927c0fa600055600160035200 +28259b787a771ce6a0442343dd8508b2f94ae391ba33b12365bbc17035c31e86=600160035260406000604060007310000000000000000000000000000000000000036201d4d4f450600160035200 a05c66c87a3743060902db9fba58f6c002ba1225a11fd85c2910fa251231a54f=60016003526040600060406000731000000000000000000000000000000000000002620493e0fa50600160035200 +f2b73c66f8a6365168230f9d8247a482c901ecbbdbe08004170c0f3db9e37930=6040600060406000731000000000000000000000000000000000000002620493e0fa00 +be303a6b604153d86b8c041aee03c5165c4bab158dabd63ee408e525b9f7075b=60406000604060007320000000000000000000000000000000000000016207a120fa60005500 cc253b8464df96b5902144db47ffe52e42c74685b5e822b763190c301567b369=6040600060406000732000000000000000000000000000000000000002620493e0fa00 1fc33a3065a274a1c4731b2fff9fc4675309e557131d61b3b7700559fef1e467=604060006040600060007320000000000000000000000000000000000000036201d4d4f200 afb1b47797335e53cdc9467108080e6922ad005f3893e38d751df01e2d0998ae=604060006040600060007310000000000000000000000000000000000000036201d4d4f200 -be303a6b604153d86b8c041aee03c5165c4bab158dabd63ee408e525b9f7075b=60406000604060007320000000000000000000000000000000000000016207a120fa60005500 -f2b73c66f8a6365168230f9d8247a482c901ecbbdbe08004170c0f3db9e37930=6040600060406000731000000000000000000000000000000000000002620493e0fa00 -4fe53d29306665adcdc638aac6d0830318fcb19dd679c4978ddc158a39fe62ce=604060006040600060003562092856fa600055600160015500 722d286ead0dd8fb456e399a368af1ff1c3d3fda619eeee098f598331525ec43=604060006040600073100000000000000000000000000000000000000262061ad0fa505b61c3506080511015603f5760013b506001608051016080526023565b00 -e1e34b26e94d0b8a399a402d540ce9f6e2db126c89fe0cde67f9b2f4a6f2268f=604060006040600060007310000000000000000000000000000000000000036201d4d4f200 +4fe53d29306665adcdc638aac6d0830318fcb19dd679c4978ddc158a39fe62ce=604060006040600060003562092856fa600055600160015500 b7e895641c3007eb44a637b315aaab9539bd1209e7ad346ef2f9e80fd3b28d24=604060006040600073100000000000000000000000000000000000000262061ad0fa50600160035500 -4624e38fce300e82ef08e25d4899c2466721ac24f7c5ea4a9fe205a62f59ae1d=6001600352604060006040600073100000000000000000000000000000000000000262061ad5fa50600160035500 -81a3559f95be565bc43fdfbd30daa82a89fc86a2e92f2b9e23981bfd8f76c8c9=600160035260406000604060007310000000000000000000000000000000000000036201d4d4f450600160205200 +e1e34b26e94d0b8a399a402d540ce9f6e2db126c89fe0cde67f9b2f4a6f2268f=604060006040600060007310000000000000000000000000000000000000036201d4d4f200 e9b485a251e321f74d917400db4546485a0fb9f5fecd094bae4a389c2ef43eef=6001600352604060006040600073100000000000000000000000000000000000000262061ad5fa505b61c350608051101560445760013b506001608051016080526028565b00 +81a3559f95be565bc43fdfbd30daa82a89fc86a2e92f2b9e23981bfd8f76c8c9=600160035260406000604060007310000000000000000000000000000000000000036201d4d4f450600160205200 +4624e38fce300e82ef08e25d4899c2466721ac24f7c5ea4a9fe205a62f59ae1d=6001600352604060006040600073100000000000000000000000000000000000000262061ad5fa50600160035500 f31c205d634922344829da12de3086733e58f603fc31710c158ae456b674e668=604060006040600073100000000000000000000000000000000000000262061ad5fa505b61c3506080511015603f5760013b506001608051016080526023565b00 37c4eee477383998a832fdf28353f590e48b27123b300ed399f77700b5978111=604060006040600073100000000000000000000000000000000000000262061ad5fa50600160035500 74962fff62c0a4ce03d6cd31c1a58b749a196d66f630dbeb9629ac96720e0e53=604060006040600060003561eaf6fa600055600160015500 8978a0facc7ef4be4cbc5d2efd03de84172f3a1d8ac0bf9d139cf395e97dc94b=60406000604060007310000000000000000000000000000000000000036201d4d4f400 7230fdd3981b30ed76ae2d327857920cc937ed84661768eb1accfa1e54af4027=604060006040600073100000000000000000000000000000000000000262061ad0fa505b61c3506080511015603f5760013b506001608051016080526023565b00 +7d0f9af9265451fd3a0b5f7ee1b9aedd7995514c8a1e0fee49bba65b1b0dac43=6000356000526040600060206000731000000000000000000000000000000000000001620927c0fa600055600160015500 3174b7ef817680780a83ec454c7bcc5f4e9ea56d126b34a8b0eb3a08d0da64bc=5b61c3506080511015601c5760013b506001608051016080526000565b604060006040600060007310000000000000000000000000000000000000036201d4d4f200 -dfe22b1d3adeb26a4aae00560b744af4e53df3590769e33b40ae24a161a2d7ca=6001600155604060006040600060007310000000000000000000000000000000000000036201d4d4f200 17e38df7ed7bc33d107911adb4149ad591f78f654ab9f3108e7f4eb129ae545d=600035600052604060006040600060003562061ad0fa50600160205200 -7d0f9af9265451fd3a0b5f7ee1b9aedd7995514c8a1e0fee49bba65b1b0dac43=6000356000526040600060206000731000000000000000000000000000000000000001620927c0fa600055600160015500 +dfe22b1d3adeb26a4aae00560b744af4e53df3590769e33b40ae24a161a2d7ca=6001600155604060006040600060007310000000000000000000000000000000000000036201d4d4f200 +86b171a421431c31a2203461b78bcb590c97261d0ac766f1f54935b182345557=6000356000526040600060206000731000000000000000000000000000000000000001620927c0fa600055600160015500 e3b86e973eca920d41f0bd75d8b31bf41d234e6b076fafbab5e5569c82173211=6001600352604060006040600060003562061ad0fa50600160205200 ddb2857153071a4a369737061fd85a778889ed4352e2bad25d238af15f27da16=600160015560406000604060007310000000000000000000000000000000000000036201d4d4f450600160035200 85b2d690a5cc162c8288585b95a381f31e83a3a57b5d76b331bbb5287a199f20=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060007310000000000000000000000000000000000000036201d4d4f450600160035200 -86b171a421431c31a2203461b78bcb590c97261d0ac766f1f54935b182345557=6000356000526040600060206000731000000000000000000000000000000000000001620927c0fa600055600160015500 -911368bbead45abe1065427b032be1a7be045bb631176c25902e6ae4b1431a4f=6040600060406000731000000000000000000000000000000000000002620186a0fa00 af026713c0f79ed0f9422542314b76c2d987cd460191945ade6291ddb324edcf=6040600060406000600073100000000000000000000000000000000000000361c350f250731000000000000000000000000000000000000001ff00 +911368bbead45abe1065427b032be1a7be045bb631176c25902e6ae4b1431a4f=6040600060406000731000000000000000000000000000000000000002620186a0fa00 0d5110e79e7e7f1610af81d144f95ebf1490c262b2061ac5b1abb732d64ba8e2=604060006040600073100000000000000000000000000000000000000361c350f450731000000000000000000000000000000000000001ff00 4c7bd946f52be4d844bd55901ae229f48a66a1e42d9e8a9d930426186b6b4b98=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f200 dbfcfc8a4c91780172921929c09e091ce397db603c05f886d3f79e89d6ad46ab=731000000000000000000000000000000000000000ff604060006040600073100000000000000000000000000000000000000361c350f400 -55bfae0c08eb128e982de648f2205254221e7f93b84741f952ce7faf60c6659a=6001600152604060006040600060007310000000000000000000000000000000000000016207a120f250600160025200 -1b1811f756816d2ddee4caeb1cae16252329ca9b8df4246f662aadbc43f989c2=60016001526040600060406000731000000000000000000000000000000000000002620f4240fa50600160025200 394e474a7818369aa6ef906be0c6644a95a9e29478f9cfbaa2a03daea59ec68c=6001600152604060006040600073100000000000000000000000000000000000000163017d7840fa50600160035200 -031cbc6008876a2d3377154417571f4bd0a820a4b3ebc05da64fe4fb644a91bf=60016001526040600060406000731000000000000000000000000000000000000002620f4240fa506001601f5200 +1b1811f756816d2ddee4caeb1cae16252329ca9b8df4246f662aadbc43f989c2=60016001526040600060406000731000000000000000000000000000000000000002620f4240fa50600160025200 +55bfae0c08eb128e982de648f2205254221e7f93b84741f952ce7faf60c6659a=6001600152604060006040600060007310000000000000000000000000000000000000016207a120f250600160025200 913cd9fcc69b0cf2717ce54e52ff7877c6e8ec8f533d876543d5c3e139b02ae8=6001600152604060006040600073100000000000000000000000000000000000000163017d7840fa506001601f5200 +031cbc6008876a2d3377154417571f4bd0a820a4b3ebc05da64fe4fb644a91bf=60016001526040600060406000731000000000000000000000000000000000000002620f4240fa506001601f5200 86543023e3a738c6eed5c0789fced34f74e0df473c78279763720c442e2449ac=600160015260406000604060007310000000000000000000000000000000000000016207a120f450600160155200 1eead44955d81c4eb2d0d7701f660a59433e9b3772dac184e3fab15e1df3aa47=604060006020600060027310000000000000000000000000000000000000026203d090f200 3911b30490a024a2f85a5a6c7e83be797ba997cf4865c1ee1a12000990c863fc=600035600052604060006020600060007320000000000000000000000000000000000000026203d090f200 -b4240ea416e844fc377d42e2baf78f2786934b0b4a0297accacecb853e036fe4=604060006020600073100000000000000000000000000000000000000162055730fa00 91ca3f0a794a613cb00a5af2f8b9b51f435bb74f6aedd6a0fdc67d32c548d487=631122334460005200 fa604d7cc74787b4e22cc5feeca594bd39651e1edaa4fd04713fa589e3111a36=600060006000600060006000355af2600055600160015500 bc9d5eb5e687e81d4337eebe298cf5ac56ba9af338be51564798fdf4629f9586=604060006020600073200000000000000000000000000000000000000162055730fa00 -c32a492feef390c6e2ebdcf786710b75f0249803127aa9cc425195423625c4eb=60406000604060006000600035614e34f200 +b4240ea416e844fc377d42e2baf78f2786934b0b4a0297accacecb853e036fe4=604060006020600073100000000000000000000000000000000000000162055730fa00 e3fb774d92546b939d025710375a6f30e2878f68981bdfd0d7ad941ee5b8077a=6000356000526040600060206000731000000000000000000000000000000000000001620249f0fa600055600160015500 +c32a492feef390c6e2ebdcf786710b75f0249803127aa9cc425195423625c4eb=60406000604060006000600035614e34f200 d90ca2ba7240aa1702a9340556d3b024e2ca470fec0a3e5c001f1bcdfafda78c=6040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 3a891e03c400cb4fb705e70bebbb1467bf91e052c1e435b21d9bd7488851fdfd=6040600060406000600073100000000000000000000000000000000000000261c350f250731000000000000000000000000000000000000000ff00 941d4ad354c546f28461fe3422f954a5d8c347d075d192ca40fe1a0e4b136b37=604060006040600073100000000000000000000000000000000000000261c350f450731000000000000000000000000000000000000000ff00 +28a8dbcbc1d87f9fde6d57eca021a131effe99fb866ec78a845c85a37c1bb212=600160035260406000604060007310000000000000000000000000000000000000036203d090fa50600160035200 28debc2190ba10fe2437f4826b554e8c2983a2613eea29bd17a61b38b202cee6=60016003526040600060406000731000000000000000000000000000000000000002620493e0f450600160035200 7fd91a367a1410a3d1a44cfcdda30bf0bffc24c9fb7d8f28d4cda4aebf7f0151=600160015200 ffd7cbda91ff075896082246f9efe599b8ce72bf6dbcfa5463fab4834e385b37=604060006040600073100000000000000000000000000000000000000162055730fa600055600160015500 -28a8dbcbc1d87f9fde6d57eca021a131effe99fb866ec78a845c85a37c1bb212=600160035260406000604060007310000000000000000000000000000000000000036203d090fa50600160035200 755f1aa3078eab6342ea35bb1c5ebd1f6dba37cf197a46931cb3502703e50523=604060006040600060003562055730fa600055600160015500 8cd5f1da0a54544f60ab0932eb3a546866e047ad1b287cebc999bfad87b20908=60406000604060006000731000000000000000000000000000000000000002620493e0f200 f3315867b1ff03330818d4979ec692d60632b26a926cb8f04060bd2297d4a592=60406000604060006002731000000000000000000000000000000000000002620493e0f200 01110d9d56ce4b24560dfdc4cd4079811e32e4e2845bf7b7f1fa6ff7bb98d189=60406000604060007310000000000000000000000000000000000000036203d090fa00 +efd3791362262abf08729a7d7eed41b0b9e211ee0d7e2d63e26dfafa8dd3605b=60406000604060007310000000000000000000000000000000000000036201d4d4fa50600160015500 7106b6684160e262c6124439eed57fb5417859e6fe917de72eb194bde1f294f2=60406000604060007310000000000000000000000000000000000000036201d4d4fa505b61c3506080511015603f5760013b506001608051016080526023565b00 e6cec50e7f4fd14feca1d0152300545600b9184f9af222b92ee1ea39705a6b5f=60003560005260406000604060007310000000000000000000000000000000000000016207a120fa600055600160015500 -efd3791362262abf08729a7d7eed41b0b9e211ee0d7e2d63e26dfafa8dd3605b=60406000604060007310000000000000000000000000000000000000036201d4d4fa50600160015500 9d493cf39585e380242a5e78d876bb72bc7a6e1932d14388f8707f4edc2eb4b5=6040600060406000600035620493e0f450600160015200 959780bdbe849e75c2983634a537636aa539fc57bac17f51354eff7a8442415a=60406000604060006000356201d4d4fa00 +3eeda39518c12c58d883cee18c09bf06998f0e8cc586a87c6ae2f1e8dee4cff7=5b61c3506080511015601c5760013b506001608051016080526000565b00 f61c7e415147d3786daec93e883995af444dc4b87d9f5e2fc90f247d7a31c4cd=6000356000526040600060206000600073100000000000000000000000000000000000000262030d40f200 c3c01fcf216aa9d8a37eaddf379db38ae881981f63616b2d2e460bc0a5cd5bcb=600035600052604060006020600073100000000000000000000000000000000000000162055730fa600055600160015500 -3eeda39518c12c58d883cee18c09bf06998f0e8cc586a87c6ae2f1e8dee4cff7=5b61c3506080511015601c5760013b506001608051016080526000565b00 -6612d3591ca5cff6424dfc7ecf672bd0476b338f0c45349467e83ebdf8180dc9=6040600060406000600073100000000000000000000000000000000000000262061ad0f250600160015500 -36d372f01e14a26d3739f0a66ab218dce8adf2fe7d8f7663672aa209bfc501ef=60406000604060007310000000000000000000000000000000000000036201d4d4fa00 2626635253531004e0083e5ab107a55b0da18c00d0e63d11dd231f922b3a64a0=604060006040600060003561eaf6fa600055600160015500 +36d372f01e14a26d3739f0a66ab218dce8adf2fe7d8f7663672aa209bfc501ef=60406000604060007310000000000000000000000000000000000000036201d4d4fa00 e351411758140bbda208c47f21a717c14592bb69887f75acb72450640718fafe=6040600060406000600073100000000000000000000000000000000000000262061ad0f2505b61c350608051101560415760013b506001608051016080526025565b00 +6612d3591ca5cff6424dfc7ecf672bd0476b338f0c45349467e83ebdf8180dc9=6040600060406000600073100000000000000000000000000000000000000262061ad0f250600160015500 +2a9cd3f540828b9d7f10518a4986822deaef29110d4a4e9b214167d3dd422135=60406000604060007310000000000000000000000000000000000000036201d4e8fa00 27711706af4e7c525eb52c15796c712d0c11e595ec37fe8e85a91c401f6b4191=604060006040600073100000000000000000000000000000000000000262061ad0f450600160035500 7016b75b4fe8b619967eb8c1368c2465918b0165d4c5704c54e0be85982c1e69=604060006040600073100000000000000000000000000000000000000262061ad0f4505b61c3506080511015603f5760013b506001608051016080526023565b00 -2a9cd3f540828b9d7f10518a4986822deaef29110d4a4e9b214167d3dd422135=60406000604060007310000000000000000000000000000000000000036201d4e8fa00 4d1c50f95e2e5a62d0d80afa50d74bf47549c34141e979880ba45ed74c09380a=6040600060406000600073100000000000000000000000000000000000000262061ad0f250600160035500 -f0165c8201e02783fc98137d70eaf711d12c99d88ddfc41ddedf99443e54d612=6000356000526040600060406000731000000000000000000000000000000000000001620c3500fa600055600160015500 -b77cbcf2dc17a2d2e64fd93462fae09f85f9441231f9e1011807b7f92ae2dc80=6040600060406000600060003562061ad0f200 a3fc2a1912421434d65d63c44b9276655cfdcd7b63f2ad5aebde3a6eb1871f91=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060007310000000000000000000000000000000000000036201d4d4fa00 79d11cbc7e13370c339c4b6cf861c79ea723d013dc56ce97450cd3123d80b801=60016003556040600060406000731000000000000000000000000000000000000003614e34fa00 -9c05c56c35679d36fbefc4cfedf1eb9eec0ec59f91f8314511afa4ddd53a4d79=600160035560406000604060007310000000000000000000000000000000000000036201d4d4fa00 +b77cbcf2dc17a2d2e64fd93462fae09f85f9441231f9e1011807b7f92ae2dc80=6040600060406000600060003562061ad0f200 +f0165c8201e02783fc98137d70eaf711d12c99d88ddfc41ddedf99443e54d612=6000356000526040600060406000731000000000000000000000000000000000000001620c3500fa600055600160015500 7ef175fe7268e1628cbe09e3bffb1760c2d2642000ff5a2fadd85aa2b4e2fab4=604060006040600060003562061ad0f400 a71d4709c30594846e170a0199776c922f7a2f3053bd4c4623195f33d8354880=5b61c3506080511015601c5760013b506001608051016080526000565b6040600060406000731000000000000000000000000000000000000003614e34fa00 -330bcfcd9070b4879165e359c0952305d4b5de189f5b283b73556d46c8aa89fe=60406000604060006000731000000000000000000000000000000000000002620186a0f200 +9c05c56c35679d36fbefc4cfedf1eb9eec0ec59f91f8314511afa4ddd53a4d79=600160035560406000604060007310000000000000000000000000000000000000036201d4d4fa00 898daa0dde418d103f87750e94ad28510cf1d2c3eaa2019adb161607c3f345cc=604060006040600073100000000000000000000000000000000000000361c350fa50731000000000000000000000000000000000000001ff00 +330bcfcd9070b4879165e359c0952305d4b5de189f5b283b73556d46c8aa89fe=60406000604060006000731000000000000000000000000000000000000002620186a0f200 0ca686a3596a517253fb3eed546559ea48bafe95f1255e56636e57ce9b4f206d=6040600060406000731000000000000000000000000000000000000002620186a0f400 81ce17c01b81feaac753e31bbaa6c5962927200ac16e21614ed904a5aa58ba59=731000000000000000000000000000000000000000ff604060006040600073100000000000000000000000000000000000000361c350fa00 -aa752032f8023793e2ce90a566d8261ce682b60cdd57dea16d2faf17ba0e0530=604060006040600073100000000000000000000000000000000000000163017d7840fa600055600160015500 -2345251fc06998d6100c332efdce916fd61069881ca2746b9e7fccb71889ae97=60406000604060006000731000000000000000000000000000000000000002620f4240f200 ad8b9a8ada9cbea6549060796d360654180d999b61ce823716bc6dccb3eb130b=60406000604060007310000000000000000000000000000000000000016207a120fa00 +2345251fc06998d6100c332efdce916fd61069881ca2746b9e7fccb71889ae97=60406000604060006000731000000000000000000000000000000000000002620f4240f200 +aa752032f8023793e2ce90a566d8261ce682b60cdd57dea16d2faf17ba0e0530=604060006040600073100000000000000000000000000000000000000163017d7840fa600055600160015500 b91f8f6f60072a26c6702cc3940f64a191ee88199bde844e7320eba342270219=60406000604060007310000000000000000000000000000000000000016207a120fa00 a8b4e47486764e10c92491f389d0e9f039c49387f0bfc4f7b0cddc13ed91d258=6040600060406000731000000000000000000000000000000000000002620f4240f400 d737cfe4f473b358e4bbf25b675defdfbad5d0feb5e579fa2a6bd8b8e33cb928=604060006040600073100000000000000000000000000000000000000162055730fa600055600160015500 15427cf6c2f1cda400a5e22ae9352fbbcde451223c2ba8874824fc20ee3831e2=60016001526040600060406000731000000000000000000000000000000000000002620493e0f450600160015200 f2d6dba9b905bd2faa31322899c65419ba6fec6a6e2ced2f1dd968952b410dcd=6001600b5260406000604060007310000000000000000000000000000000000000036203d090f4506001600b5200 +a83f4b1e886937bf2e59f33acd445d05b75c06e7fca6a40cf211fca04cc46035=600035600052604060006040600073100000000000000000000000000000000000000162055730fa600055600160015500 f0bf62e3b1074f38f203640db7bbdb0cd29f2d7da3cda308f15cde20e882bac9=60406000604060006000600035620493e0f200 7e7a1fbba5a24ab8b99a1c587c7f936f2d6c9173affaa3fdec27dde16301ee71=604060006040600060007310000000000000000000000000000000000000036203d090f200 de74252bf18ef8d8ef2a0c4426609537173ab8e6b8a8267f4aa024512551a308=604060006040600060017310000000000000000000000000000000000000036203d090f200 -a83f4b1e886937bf2e59f33acd445d05b75c06e7fca6a40cf211fca04cc46035=600035600052604060006040600073100000000000000000000000000000000000000162055730fa600055600160015500 +9e5fa0550d8e6448c9d7ed44098020a5d8259fb54c0df41c4e49b80b87f0fff7=6000356000526040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 6a0b6c3956ea8d7f09ceb59ffd67d87ab7c83ed2ea24c18dd36fa368927b68d9=6000356000526040600060406000731000000000000000000000000000000000000002620186a0f400 9e493073ffb1d3f2fafa1ab6c4e12c8d50e90b7f6c5f8265bcabe708a1d3f49a=6040600060406000600035614e34f400 -9e5fa0550d8e6448c9d7ed44098020a5d8259fb54c0df41c4e49b80b87f0fff7=6000356000526040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 -d785046261ef2b2c902e001004a68d692bd4ef92f80a1ad2d038c947bcf79b30=600b60035260406000604060006001731000000000000000000000000000000000000003614e34f2506001600d5200 be3c1b374105a1ad263bf482a34d194340e256d9e9caffae33a1d8eac752de9b=600b60035260406000604060006000731000000000000000000000000000000000000003614e34f2506001600d5200 +d785046261ef2b2c902e001004a68d692bd4ef92f80a1ad2d038c947bcf79b30=600b60035260406000604060006001731000000000000000000000000000000000000003614e34f2506001600d5200 773de79017408de6196b8092ec68a270308777e85196fb7f8d7a3adf15eaf984=600160035260406000604060006000600035620186a0f250600160035200 +716e7b90937b670d0f8861902e63aa3ca135e3bb31db95139ed4dcff4516d0ad=60406000604060006000731000000000000000000000000000000000000002619c90f2505b61c350608051101560405760013b506001608051016080526024565b00 2ad769b31a685c24a9813ff218ab0c162e73904096cee987a83cbc91f7910ac6=60406000604060006000731000000000000000000000000000000000000002619c90f250600160035500 3ee90542e7dac7319fdc339bca415439887d15ba46aef52574fb4fd444e1736a=60406000604060006000731000000000000000000000000000000000000003614e34f200 -716e7b90937b670d0f8861902e63aa3ca135e3bb31db95139ed4dcff4516d0ad=60406000604060006000731000000000000000000000000000000000000002619c90f2505b61c350608051101560405760013b506001608051016080526024565b00 +63ddc6c7cde8118fe54c30fd9fc1cb826c13964e4e018ed18a95115d1f667420=60016001526040600060406000731000000000000000000000000000000000000002619c90f450600160035500 9bd2b9edcce1e8c22477108d177cf7bb0a8c937fd056509b0e3813f861660733=604060006040600060003561eaecfa600055600160015500 6a377ab9663a733e2d19a51cc67035ed2cf988848e1958613920c61678d8981b=60016001526040600060406000731000000000000000000000000000000000000003614e34f450600160015200 02a39c0ea5cfcd25758f8478f2eed90a6cf897e5f78fa2ac736d5a14e76ddbe9=60016001526040600060406000731000000000000000000000000000000000000002619c90f4505b61c350608051101560435760013b506001608051016080526027565b00 -63ddc6c7cde8118fe54c30fd9fc1cb826c13964e4e018ed18a95115d1f667420=60016001526040600060406000731000000000000000000000000000000000000002619c90f450600160035500 -e10487259f293e94299500b7b3ae77caa62ff12bd1558573151cca375536d2c9=60016003526040600060406000731000000000000000000000000000000000000003614e34f450600160035200 19344224a8deb0fa8e82e94a09aeb02e7e820970a78c254a0cbc8a70621232f9=60016003526040600060406000731000000000000000000000000000000000000002619c90f450600160035500 +e10487259f293e94299500b7b3ae77caa62ff12bd1558573151cca375536d2c9=60016003526040600060406000731000000000000000000000000000000000000003614e34f450600160035200 0a2c796d5cbdaf129fb6d80cf80513a1dd595b0c5f675d754ff0e658d3c09154=60016003526040600060406000731000000000000000000000000000000000000002619c90f4505b61c350608051101560435760013b506001608051016080526027565b00 +c30f2919b4c2b7d30b6872d74fea80089c40b9fd88392074e369dd88a6e8ac78=600160035260406000604060006000731000000000000000000000000000000000000002619c90f250600160035500 2e49a6a0d257b972358b3b47343bf3fca517c29627ae610a084eba25df4b3665=600160035260406000604060006000731000000000000000000000000000000000000003614e34f250600160205200 f927fe9f4febe484192375e0cb1a95db93295e98d2d2ff5114dae3a562cf76fc=600160035260406000604060006000731000000000000000000000000000000000000002619c90f2505b61c350608051101560455760013b506001608051016080526029565b00 -c30f2919b4c2b7d30b6872d74fea80089c40b9fd88392074e369dd88a6e8ac78=600160035260406000604060006000731000000000000000000000000000000000000002619c90f250600160035500 -cf91a54add743885c763456b67470db07e8637c921d01d36d02dc8147b41aa45=600160205260406000604060006000600035619c90f250600160205200 -1035e4a30d74279c5322335b9a804376a8791f7704fee5e5e2abe2c8a69a4a25=600160035560406000604060006000731000000000000000000000000000000000000003614e34f250600160205200 -2bc0daa50656548f8bb288c4162fe1ff516e80f60357203625403a33391f58d6=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060006000731000000000000000000000000000000000000003614e34f250600160205200 4996d25cdcb6aee5f3542bb02aef18224e2ce46faf8d21484b6cf4fddbaef153=60406000604060006001731000000000000000000000000000000000000003614e34f250600160205200 +1035e4a30d74279c5322335b9a804376a8791f7704fee5e5e2abe2c8a69a4a25=600160035560406000604060006000731000000000000000000000000000000000000003614e34f250600160205200 36ef1ee3541797068fa8fb591658e5247ff437d1039a9ea43e8e6a92f0e67158=600160205200 +2bc0daa50656548f8bb288c4162fe1ff516e80f60357203625403a33391f58d6=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060006000731000000000000000000000000000000000000003614e34f250600160205200 +cf91a54add743885c763456b67470db07e8637c921d01d36d02dc8147b41aa45=600160205260406000604060006000600035619c90f250600160205200 596076fbb6f5a523e367c612a3f0a760389aa32b2e2c3c493e08f293709284a6=5b61c3506080511015601c5760013b506001608051016080526000565b6040600060406000731000000000000000000000000000000000000003614e34f450600160035200 -0d282f2ca4d6fa58b776906b97ec17f4320c928bef222d3bc31c47c3ebb5cfdb=60016003526040600060406000600035619c90f450600160035200 -c80166c3731db7b3358f05e480910feacd1b883cd4bd69168a23aceec1707a9f=6000356000526040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 aa174be1ab553fb83733662264927bf27e9a130167b31b2b2b65d2d7ac664604=60016003556040600060406000731000000000000000000000000000000000000003614e34f450600160035200 -9302404ae67eacca7bccb8ce9db8ad39bb93f78aa516219470c0ee3cbb4846e9=60016003526040600060406000600073100000000000000000000000000000000000000361c350f250731000000000000000000000000000000000000001ff00 +c80166c3731db7b3358f05e480910feacd1b883cd4bd69168a23aceec1707a9f=6000356000526040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 +0d282f2ca4d6fa58b776906b97ec17f4320c928bef222d3bc31c47c3ebb5cfdb=60016003526040600060406000600035619c90f450600160035200 c3b941b3fe17595e21ebc4a42723044fe3e8a9b8b31da85497b7d2b6e2d4987a=600160035260406000604060006000731000000000000000000000000000000000000002620186a0f200 -c0cc692ef46a185404ff734f2c5076bfda4a55fa1ea5cf1dbea81af30b8ae7f6=600160035260406000604060006000731000000000000000000000000000000000000002620186a0f250600160035200 +9302404ae67eacca7bccb8ce9db8ad39bb93f78aa516219470c0ee3cbb4846e9=60016003526040600060406000600073100000000000000000000000000000000000000361c350f250731000000000000000000000000000000000000001ff00 bc19b7fd8dc1fa147fecd948973aceb2960745fbc40991f8d09f3dda415c4269=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f250600160035200 +c0cc692ef46a185404ff734f2c5076bfda4a55fa1ea5cf1dbea81af30b8ae7f6=600160035260406000604060006000731000000000000000000000000000000000000002620186a0f250600160035200 485db9468861ff56fb336a5a134619fe32ee06fe7753ce1dae5c6e7cd893a531=731000000000000000000000000000000000000000ff604060006040600073100000000000000000000000000000000000000361c350f400 540ce432b3faf56301cbb2a9c10c084662a44e8bfb4ed0f8fd05c63c3d4a61ee=604060006040600060007310000000000000000000000000000000000000016207a120f200 f0da9c01ce06dfb829b58182a0fb24e3568c3553534c74abb063a3e8832be49b=60406000604060007310000000000000000000000000000000000000016207a120f400 @@ -2682,102 +2682,102 @@ b48d38f93eaa084033fc5970bf96e559c33c4cdc07d889ab00b4d63f9590739d=00 e466181d4de18c6565740a948ed375a7fe9891a0a75399242ff737c26a856b26=604060006040600073100000000000000000000000000000000000000162055730f4600055600160015500 3d8f4bb3dad33ace4a8f7c6913646815b69d3c1f09dafd0d559582cec2d9d128=600160015260406000604060007310000000000000000000000000000000000000026203d090fa50600160015200 70e7b30188c10f3b74489ef379faa66340e65da8a80808b6c818c6822a8d1896=6040600060406000600173100000000000000000000000000000000000000162055730f2600055600160015500 -af8497642fe2691e45cea7806fb7b32ca3118f9f0b9ea95d1efea3333ec1dde4=6040600060406000600035614e34fa00 c9e0efef6051a60fe41b11d60c4251dc7550f8130b97eab201a4722069a4fa0e=600160025500 6f2c9e67d2547208275b4ab871e237a4fa918163569ac8080ee96f1ca5caa8a3=6000356000526040600060406000731000000000000000000000000000000000000001620249f0f4600055600160015500 -36c09a0105dba101675477518b5de0f40ee543c20ebd216334a2136c0dd96bda=60016002526040600060406000600035614e34fa50600160205200 +af8497642fe2691e45cea7806fb7b32ca3118f9f0b9ea95d1efea3333ec1dde4=6040600060406000600035614e34fa00 f5e209b303eade212f36f01b21e7b5a8ced3d863f2dca92d731ef404e65fb2d5=60003560005260406000604060006000731000000000000000000000000000000000000001620249f0f2600055600160015500 +36c09a0105dba101675477518b5de0f40ee543c20ebd216334a2136c0dd96bda=60016002526040600060406000600035614e34fa50600160205200 49a03e4a082ceed2f4d0ee0743159847cf4e90384f831ff9522dc5e54263f47a=604060006040600073100000000000000000000000000000000000000261c350fa50731000000000000000000000000000000000000000ff00 73b9beefffb6fc59d657c5cf1f65ad598588720d2293468e99ba84c0c199059a=604060006040600034731000000000000000000000000000000000000001620249f0f26000555a60015500 a4d8ac63bba5d1407cc90474aa760b25476191f9bfdb3ea3f205e30b83be56f7=6000356000526040600060406000731000000000000000000000000000000000000001620249f0f46000555a60015500 7cff0f681f55e309bc5b0b5558d7a0ea013598dae7dfe9d850a4aa2cdd29c9ba=604060006040600060003561c350fa50731000000000000000000000000000000000000000ff00 -7b74af78ab90454c7ba643be2a669f5126394b0bbd9aeafbd9c5d62a02968823=604060006040600073100000000000000000000000000000000000000162055730f4600055600160015500 0f7018e4aefce00bec400639dbdeb88233c6c34d4173b8d0361ffc2848a818fe=600160015200 +7b74af78ab90454c7ba643be2a669f5126394b0bbd9aeafbd9c5d62a02968823=604060006040600073100000000000000000000000000000000000000162055730f4600055600160015500 56b70cdab35a44498f8c30f51b124841bcc612585f42bf683ed7139a989367a6=6040600060406000731000000000000000000000000000000000000002620493e0fa503360055200 9369ca7656de8f96762b8b91431e9369c02656fd26053c627b454af8ceb9a4c1=60406000604060003473100000000000000000000000000000000000000162055730f2600055600160015500 -7ba813acda194fe4b62fee350fd3020f5c5b45160abcfb6e51889fcc8b37f9c1=600035600052604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 9fa0d03017a2bcf1443caec9cf50043d73e5fd1740909380d1500bdae39b9aef=6000356000526040600060406000731000000000000000000000000000000000000002620186a0fa00 -510e52c221c015efc381ac34678af05fff9fbba15fecf7c3210fe7de502df981=6040600060406000602035614e34fa50600160035200 +7ba813acda194fe4b62fee350fd3020f5c5b45160abcfb6e51889fcc8b37f9c1=600035600052604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 6c613adfea0dcd0824ed27114194787fcc267c40244035702c8f4715cea14784=6000356020526040600060406000731000000000000000000000000000000000000002620186a0fa50600160035200 -9f20298822a4958cf1dc738403369d631e04e8934953235e2344f9bdff9deec9=60406000604060003460003562092856f2600055600160015500 +510e52c221c015efc381ac34678af05fff9fbba15fecf7c3210fe7de502df981=6040600060406000602035614e34fa50600160035200 36820aea6f9402e8239f60a98c9450a4cf2b442a09539cb500a85e1506706b8b=60406000604060007310000000000000000000000000000000000000036201d4d4fa00 +9f20298822a4958cf1dc738403369d631e04e8934953235e2344f9bdff9deec9=60406000604060003460003562092856f2600055600160015500 d268180b298019481d7be10ba1cd08c80afc5214321ad815d093e9d5dad384ad=604060006040600073100000000000000000000000000000000000000262061ad0fa505b61c3506080511015603f5760013b506001608051016080526023565b00 +8b8fdfc6b0a8d4adef57eff09c997bcf3b5fb8cd1a189decbcd53fb9f7e3687c=60016003526040600060406000731000000000000000000000000000000000000003614e34fa50600160205200 f128aff3de450169fb369b813d485683dd3542f6beef48d4f8c12d7b0fb18212=604060006040600073100000000000000000000000000000000000000161eaf6f4600055600160015500 32e4d943aca0578baa32c4b55935067c1774d4b9796d92976c027dd5b1bd78ae=60016003526040600060406000731000000000000000000000000000000000000002619c90fa505b61c350608051101560435760013b506001608051016080526027565b00 -8b8fdfc6b0a8d4adef57eff09c997bcf3b5fb8cd1a189decbcd53fb9f7e3687c=60016003526040600060406000731000000000000000000000000000000000000003614e34fa50600160205200 -614bcbeebf85626b016baa47ccb56a6ac8e749a7a3bc1e69503c60ea642d082a=6001600352604060006040600073100000000000000000000000000000000000000262061ad0fa505b61c350608051101560445760013b506001608051016080526028565b00 0f46598e2e1e8f98d1241e8eada22e112d94cfb3121a4c6ff54a674af11703ab=604060006040600073100000000000000000000000000000000000000162092d9cf4600055600160015500 de1bb63e65cd0796c21f393b4cc896526bb1fb32f87fe77995c7646757ee59f2=600160035260406000604060007310000000000000000000000000000000000000036201d4d4fa50600160035200 +614bcbeebf85626b016baa47ccb56a6ac8e749a7a3bc1e69503c60ea642d082a=6001600352604060006040600073100000000000000000000000000000000000000262061ad0fa505b61c350608051101560445760013b506001608051016080526028565b00 0a907ef25f7ec3a7649fde0fc3bde1d5c600f6c6d3e0166d840549736ec07cd3=60406000604060003473100000000000000000000000000000000000000161eaf6f2600055600160015500 -fbec71cba80e73df867097de0d4ee932071a8150cab693f5a7a93c089aaad60e=60016003556040600060406000731000000000000000000000000000000000000003614e34fa00 cd24eeb6ba19cd96b7c1843d903213377f400d5cd3a37704e5497c71a2ca035d=600035600052604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 +fbec71cba80e73df867097de0d4ee932071a8150cab693f5a7a93c089aaad60e=60016003556040600060406000731000000000000000000000000000000000000003614e34fa00 6ecb6187005c1b52d5b1b9c27a968488e5af836a2d06d8dec268f03faf4c064e=60016003526040600060406000600035619c90fa00 94249ff02157f717f6ea8ca94d3a8d7de38cbad39ec8293b7276d5d891f93b40=5b61c3506080511015601c5760013b506001608051016080526000565b6040600060406000731000000000000000000000000000000000000003614e34fa00 -a4c0ee0e96648cc50ca53228a42f432658166d070a9d4c149b902f04cf644363=60016003556040600060406000731000000000000000000000000000000000000003614e34fa50600160035200 +260f4e68033d4e00ac9ef749d006bf7415e8ff70b8d7c91edb81c19effae4f86=6000356000526040600060406000731000000000000000000000000000000000000001620249f0f4600055600160015500 350b386a63491778e8c5deba52e39331d598d4b288cf4c08991fa7b766d1e348=6040600060406000600035619c90fa50600160035200 1ca2139ddaff3045190c85c3f1a62f93cc328a8867c22e2d16974d051bc4dab4=5b61c3506080511015601c5760013b506001608051016080526000565b6040600060406000731000000000000000000000000000000000000003614e34fa00 -260f4e68033d4e00ac9ef749d006bf7415e8ff70b8d7c91edb81c19effae4f86=6000356000526040600060406000731000000000000000000000000000000000000001620249f0f4600055600160015500 +a4c0ee0e96648cc50ca53228a42f432658166d070a9d4c149b902f04cf644363=60016003556040600060406000731000000000000000000000000000000000000003614e34fa50600160035200 9e9ef6d05630957275c98645f1874d04a8386698f4b2e1c22ad2add17a3351da=60406000604060006000731000000000000000000000000000000000000001620249f0f2600055600160015500 5ea8f924946ab1da886ea3d6fb342ad2f5ad281ba4daf64e0d54ea0756dfc5c5=6001600352604060006040600073100000000000000000000000000000000000000361c350fa50731000000000000000000000000000000000000001ff00 1e8f62ea8d62323b4facebd9a33309e6be110ab045c9068a124e0743ec7b8641=6040600060406000731000000000000000000000000000000000000001620249f0f4600055600160015500 23de4e424220ffefefb2130e496ec18b778b07e4554db256516c7bef0f969acc=604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 48133ce8c05d2a6ec8fbc4e23892bd5faf8bde675dd75064a8a3c04399e2506f=60016003526040600060406000731000000000000000000000000000000000000002620186a0fa50600160205200 -60ae939946e955ed64a55af1334be7353b16cf67154e6e993ec591dbce884498=60406000604060003473100000000000000000000000000000000000000163017d7840f2600055600160015500 3bc5208a1d4e38e24a6767941196cab880161d0f905b797d99e6280ff098613a=6040600060406000731000000000000000000000000000000000000002620f4240fa00 +60ae939946e955ed64a55af1334be7353b16cf67154e6e993ec591dbce884498=60406000604060003473100000000000000000000000000000000000000163017d7840f2600055600160015500 91a0e84c1e91aae18f142ce0292dfeb6a10163f366259318b8a919f9d414d737=604060006040600073100000000000000000000000000000000000000163017d7840f4600055600160015500 -5cb3d491a0a70a0af216a87e20fbe23ba17785d85118fdd5814c750419546197=60016001526040600060406000731000000000000000000000000000000000000002620493e0fa506001601f5200 58602048e23c946475e99fcb483028b9f4b93d658d602acfc604a7b360d609ff=600160015260406000604060007310000000000000000000000000000000000000036203d090f4506001601f5200 -4bd54fc1246bc6cdda8054b1736ad1647804b383d908d028d6018dc61eea02aa=6040600060406000600035620493e0fa00 +5cb3d491a0a70a0af216a87e20fbe23ba17785d85118fdd5814c750419546197=60016001526040600060406000731000000000000000000000000000000000000002620493e0fa506001601f5200 84d1af0c5c6c3883b3c16560eac3756318e4115fb14bdda65e718ef213c984b5=60003560005260406000604060003473100000000000000000000000000000000000000162055730f2600055600160015500 +4bd54fc1246bc6cdda8054b1736ad1647804b383d908d028d6018dc61eea02aa=6040600060406000600035620493e0fa00 1011b3270837b0bc4fbf6531f8ce57306e94efd1d9e5d3c841d40e613e60ef14=60406000604060007310000000000000000000000000000000000000036201d4d4f400 4371bec7904154375251cdb8ad720246cda44afd4265f54a97fdb17f8593f08d=604060006040600073100000000000000000000000000000000000000262030d40fa00 756d7e76b15eda302bd0da29fe9670240105b4d434b6785ad9830bc2a7c9794c=600160035260406000604060006000731000000000000000000000000000000000000003614e34f200 -da8d5432a874207132bcf3abde03605d022c018ebe7400d7875aaec2c4c00407=60406000604060006000731000000000000000000000000000000000000001620aaef6f250600160035200 -71dbc3fca2af095c1853e6d45c001c84a647976dab0596259de5ab597a35118b=60406000604060006000732000000000000000000000000000000000000001620aaef6f250600160035200 -28e88bc8516f4edf414d22533479b4b26a559189c25a285e2f2bd546c93d0045=604060006040600060007320000000000000000000000000000000000000036201d4d4f250600160035200 06fb81d18433dc0ded42d33d4464632d084b7c904e5aec9ce159f8e303bf7637=604060006040600073200000000000000000000000000000000000000262061ad0fa50600160035200 6ac0a7431d0eb3e895d3c0fadeab35226f85930c46eb9bba91d8220f2d2401ad=604060006040600060007310000000000000000000000000000000000000036201d4d4f250600160035200 -cb76cadcc46d52fe0db8a30112e78c679fa3ca3ea5ae25a1f53a5211c45302d8=6040600060406000731000000000000000000000000000000000000003614e34f450600160035200 +28e88bc8516f4edf414d22533479b4b26a559189c25a285e2f2bd546c93d0045=604060006040600060007320000000000000000000000000000000000000036201d4d4f250600160035200 +da8d5432a874207132bcf3abde03605d022c018ebe7400d7875aaec2c4c00407=60406000604060006000731000000000000000000000000000000000000001620aaef6f250600160035200 +71dbc3fca2af095c1853e6d45c001c84a647976dab0596259de5ab597a35118b=60406000604060006000732000000000000000000000000000000000000001620aaef6f250600160035200 +52c50940cc34283081c291b8240f2efe9a017c174c698ad7a1751209c8b58a4f=6040600060406000731000000000000000000000000000000000000002619c90fa505b61c3506080511015603e5760013b506001608051016080526022565b00 7ed1a2b2d590a12d61621ac6a7349a10a5571af1ec032ee3726de3887f6ed2e3=6040600060406000732000000000000000000000000000000000000002619c90fa00 -b29eebdd30e390867117f875b426663efcc56c2e1ca53e008100448daf179444=604060006040600073200000000000000000000000000000000000000161eaf6f4600055600160015500 0b3c9a8f6810a7d891a1b98f1e626517238a509f4e58a4a6ab122d81f700671b=604060006040600073100000000000000000000000000000000000000161eaf6f46000555a60015500 +cb76cadcc46d52fe0db8a30112e78c679fa3ca3ea5ae25a1f53a5211c45302d8=6040600060406000731000000000000000000000000000000000000003614e34f450600160035200 53ea926755491ecc957290dc5b2761ae0556232b03dc5471fbc718d9c844bd23=6040600060406000732000000000000000000000000000000000000003614e34f450600160035200 -52c50940cc34283081c291b8240f2efe9a017c174c698ad7a1751209c8b58a4f=6040600060406000731000000000000000000000000000000000000002619c90fa505b61c3506080511015603e5760013b506001608051016080526022565b00 -a2a239813865d7d5692bb2207007a923a27c7aad842251e6e6528820df5d2be4=60016003526040600060406000731000000000000000000000000000000000000002619c90fa50600160035200 -b7163a865729b62df082e1b4f8e8bfd1f19244f9a5341116011ddf5abb4dfa28=604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 +b29eebdd30e390867117f875b426663efcc56c2e1ca53e008100448daf179444=604060006040600073200000000000000000000000000000000000000161eaf6f4600055600160015500 8a2731d929b54f34dc0b82265e6bb2dc91bd33c186789d5e93bc8110fad0b0ea=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060006000731000000000000000000000000000000000000003614e34f200 +b7163a865729b62df082e1b4f8e8bfd1f19244f9a5341116011ddf5abb4dfa28=604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 +a2a239813865d7d5692bb2207007a923a27c7aad842251e6e6528820df5d2be4=60016003526040600060406000731000000000000000000000000000000000000002619c90fa50600160035200 707f41cf7885b5ead8e3e1ba796b727b8e466875ffba6fae98a52ed932a0c1ca=5b61c3506080511015601c5760013b506001608051016080526000565b6040600060406000731000000000000000000000000000000000000003614e34f400 2091a5db3247f6d174ad7a3becf4ffcefa1171720288653cd7e80c980fe255c4=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f200 fef2ad1bd1d0042a6efdd15783014b1af38d0e62db2d9b3f4dcb95a4102aa1f9=60406000604060003460003563017d7840f2600055600160015500 -18e71aba1fabecef860a76d397205a6226dd73c289caaa59e237037cdf3f33e4=604060006040600060017320000000000000000000000000000000000000016207a120f200 8e91a8556ca4ea7ca6e52b6207def03bc8dec91c4122be6b66bc215c78aa265c=6040600060406000732000000000000000000000000000000000000002620f4240fa00 -cafe4006fa0a33e7beb1bb618c22ee3c36be51c9b437d2eb77e10ca1db33ed20=60406000604060003473100000000000000000000000000000000000000162055730f2600055600160015500 +18e71aba1fabecef860a76d397205a6226dd73c289caaa59e237037cdf3f33e4=604060006040600060017320000000000000000000000000000000000000016207a120f200 b98a2cd25451cc59f3e145e18b860744e8a92d1c6afbc521919947b15a198ba6=604060006040600060013403731000000000000000000000000000000000000002620493e0f200 +cafe4006fa0a33e7beb1bb618c22ee3c36be51c9b437d2eb77e10ca1db33ed20=60406000604060003473100000000000000000000000000000000000000162055730f2600055600160015500 07f6a9472c712464919f59e9e8785a2c8972273b04f2370fc1e4931e65430371=600160015260406000604060007310000000000000000000000000000000000000036203d090fa50600160015200 1918a8f94735cfee2a5bd6f836f14eb12f7f43faa317b3d84aea67c96f5c2774=6001600152604060006040600060013403731000000000000000000000000000000000000002620493e0f2506001601f5200 c68361add39b3ac30cfe63fdc345f2e0712b8194b1653a6df786532ee0dfefb2=600160015260406000604060007310000000000000000000000000000000000000036203d090fa506001601f5200 -0bf40b092409d33068ede1528ed0c7589021e8e292d7dfdd15f144755b49cff9=6040600060406000731000000000000000000000000000000000000003614e34fa00 b6e6ebdd00d58b886b5d2c7c7318961b0defdd3a3c94852c1a62d6560ed9bfaa=604060006040600060013403731000000000000000000000000000000000000002620186a0f200 +0bf40b092409d33068ede1528ed0c7589021e8e292d7dfdd15f144755b49cff9=6040600060406000731000000000000000000000000000000000000003614e34fa00 a06aee939887e976a9ed735d040644f23e196c0b66bae5072e0251081b4bd3e4=604060006040600060013403731000000000000000000000000000000000000002619c90f2505b61c350608051101560425760013b506001608051016080526026565b00 -377901720af802d93c9a67ccfa9732ce496dc57a5bc06dcace058ef7bb0dc21e=6040600060406000731000000000000000000000000000000000000002619c90f4505b61c3506080511015603e5760013b506001608051016080526022565b00 9997b6fb70eb91d61dbd8d5e51e1fb06152afe9d045bd279766b8e557dadcfd9=6040600060406000731000000000000000000000000000000000000003614e34fa00 -22109675dc763fc2ff376e0489170c411a5be253e37c288fccffea224388d22e=604060006040600060013403731000000000000000000000000000000000000002619c90f2505b61c350608051101560425760013b506001608051016080526026565b00 +377901720af802d93c9a67ccfa9732ce496dc57a5bc06dcace058ef7bb0dc21e=6040600060406000731000000000000000000000000000000000000002619c90f4505b61c3506080511015603e5760013b506001608051016080526022565b00 66fd6efff22789e0022a148c485bcc4dd430c75c87a5ac0ddc84a4978d334d10=60406000604060003473100000000000000000000000000000000000000161eaf6f2600055600160015500 -6bf73fe3b9e1007d402594ae2d1ea36fb201eb90c7f68d788d81d2159cfaf582=604060006040600060013403731000000000000000000000000000000000000002619c90f200 +22109675dc763fc2ff376e0489170c411a5be253e37c288fccffea224388d22e=604060006040600060013403731000000000000000000000000000000000000002619c90f2505b61c350608051101560425760013b506001608051016080526026565b00 fc5309d4154da6030e05a30dd2ce4585118873591176f79ee402988d43297b24=604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 +6bf73fe3b9e1007d402594ae2d1ea36fb201eb90c7f68d788d81d2159cfaf582=604060006040600060013403731000000000000000000000000000000000000002619c90f200 4a20daf1922ebcc25cf82baf42ee2c532c2da74926e44894a7c7e8770abc7d81=6040600060406000731000000000000000000000000000000000000002619c90f400 92c32bd57eefaf63706894534570b803fdc3ff23c3379867f688d289566eae96=604060006040600034731000000000000000000000000000000000000002620186a0f200 21906a140b3d2329b1b977c9bdb906d61e092ce21f8f3644ea709b839e462ec4=6040600060406000731000000000000000000000000000000000000001620249f0f46000555a60015500 af9837019dc7e71ad40ad889121d58d8840f03364cfa98c910fea95cebe565e0=6040600060406000731000000000000000000000000000000000000002620186a0fa00 f6f3d117f582e9aeed2b021271206d10bb0d1122bcd53be6f33273d5d05b2852=60406000604060007310000000000000000000000000000000000000026203d090f400 -f49691185c98bc4d38cbd6f72fee8d284ae0347ac3dab980fe98fc9855053d08=60006000600060006000734000000000000000000000000000000000000004620f4240f200 ca395fbb13fec43e41a6f1dd5f292ebd9f3ba198b79e4caf0ea84aaac1116d27=604060006040600073100000000000000000000000000000000000000161c350fa00 +f49691185c98bc4d38cbd6f72fee8d284ae0347ac3dab980fe98fc9855053d08=60006000600060006000734000000000000000000000000000000000000004620f4240f200 6aaee305608773195015611678fc4b42bd9996507fffbd7646555c815b32c8ae=600160015200 d5680d1a57d65009464d64daf8a18d829b4321d52250ba8252efb41dfe013548=600060006000600060007340000000000000000000000000000000000000046103e8f200 b6854de517529726bb59d586b298c37c964c0bea333f2ae471b44beb4a230ed8=6000600060006000730f572e5295c57f15886f9b263e2f6d2d6c7b5ec66103e8fa600055600160015500 6c0e2b5b332daee1e973fdc64c85c26e3ba3989a858fa1c32cc57423045be2e6=6000600060006000730f572e5295c57f15886f9b263e2f6d2d6c7b5ec66103e8fa60005500 -318aa00ff7c3c999aec760237f43b8a15e0c221498a327b4eaf57003b2afc156=60ff6000533360206000a100 62ba2266bc159fa76122f6b060114940d17c4dcce9cdf5e4fb75cd475ceb7df3=60ff6000533360006000600060206000a400 +318aa00ff7c3c999aec760237f43b8a15e0c221498a327b4eaf57003b2afc156=60ff6000533360206000a100 cfc2b962815c543844b7b2a412adbe303fa0efa9a2e0ec93c1fbf9e231558199=60ff60005360206000a000 66ea953d8c72d0637943560c649fb4f6d540ad3cdacebd34ba592c612cdefc72=7b601080600c6000396000f20060003554156009570060203560003555600052600060006000600073aaaaaaaaace5edbc8e2a8697c15331677e6ebf0b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecfa00 5eff31ebea62b04f764a877c84c2cc92a00a13feff33ed56c575a25635dab23d=600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa61157cfa600055600160015500 @@ -2814,14 +2814,14 @@ d9ee1ed86455c4d7ca5c8734f327a0cd55d4b62cf74dc98cc5bda96e1bd7d4fe=7ffeedfeedfeedf f26b0805bac34e43cbe429c9f772f7113748e7bfeca8e39df096ed3d0552c258=6000600060006000601773095e7baea6a6c7c4c2dfeb977efac326af552d8761c350f1600101585500 ecdbcebf816bd6ffd6e9da9d9307cdd607cc57071f27d857549d810d733fd2bf=6000600060006000601773095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03f1600101585500 b94850406c5cc6921a6e6d8bde93b0f1e88973724fdc618631232ec443ff5691=6000600060006000601873945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03f1585500 -1e6a612423b1c661aecfd0d91d2339e425f91dcff078cd9d07d28c405e8bc1a6=6001600054016000556000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03f100 cf5fd0ebd61fc2dbf8dac98eabdc6b44980e07c42b6814dec77a941628bae32a=6001600054016000556000600060006000600173945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03f100 +1e6a612423b1c661aecfd0d91d2339e425f91dcff078cd9d07d28c405e8bc1a6=6001600054016000556000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03f100 b254f222c66920f0da84e3e5327cdb7a4a78e48aed4cf079f517be94be4c13bb=6000600060006000601873945304eb96065b2a98b57a48a06ae28d285a71b5620186a0f1585573945304eb96065b2a98b57a48a06ae28d285a71b5ff00 86e091a7ccdb683bac5489b99bd742053ecee5874f04a78561b6197ee5082b85=6000356000526000600060206000601773095e7baea6a6c7c4c2dfeb977efac326af552d8761c35060003503f16001015855730f572e5295c57f15886f9b263e2f6d2d6c7b5ec6ff00 f2a018a1727b04c0eed1e47c656aa734465df019c4e6cc6761d1fc43c4272558=6000356000526000600060206000601873945304eb96065b2a98b57a48a06ae28d285a71b5600035f1585500 78aa31217c88bb237260ad76d5e7b1e9466a0b5bd65e1a4e254e06f58d86991d=5b600a60805110156042576000600061c3506000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff16000556001608051016080526000565b60805160015500 -7e3b8f4e80ca8679786483f27f64ac780f82e72385fbc89b420027cc437eea9f=6001600054016000556000600060006000600030612af85a03f160015500 fa24c7c55f747597fc149cce83a02d9843f9e1dbf982d5f75e1111da358547da=6000600060006000601773945304eb96065b2a98b57a48a06ae28d285a71b56305f5e100f100 +7e3b8f4e80ca8679786483f27f64ac780f82e72385fbc89b420027cc437eea9f=6001600054016000556000600060006000600030612af85a03f160015500 97acd9b2ba21ee05bf3ac6c3a1f535f821b539c64a02322f2d71e2ade8a1fe1c=600160005401600055690fffffffffffffffffff610402600054040260025560006000690fffffffffffffffffff610402600054040260006000306104005a03f160015500 4e009047ee5311748b376c8542e67a3a2fc308addd07cc27c90724ba32b5e38d=6001600054016000556000600060006000600030613a985a03f160015500 faf42407d80f6f38660d94fbb71f781655060e1300aa15a3c783a67c0a646b7a=600160005401600055600060006000600060003060e05a03f160015500 @@ -2875,12 +2875,12 @@ b5449ad280d4b54db0bd0d5b109c28f7ddab926a8fb168387c423352e8733907=603760015500 2c1a699913984bf25854461c0a2fcf852759e7fdeb5bfbc959305b64f8245eb6=6000600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b611388f100 39dc286827f4e11b0c27330b0399837d618c349d58bc7d032fc8beddb9b24eae=600060006000600060016000619c40f100 0819cb021f81370dc3d7d14a3fa84fce82d9db2e5264e0fce4f5bc28b89dd744=600060006000600060016000620186a0f100 -2a203f69a317afd0cdf2dd1ca84a097da8a0cdda385e87a53540eee36596e3b3=7f6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9600052601b6020527f79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986040527f6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a96060526020600060806000806001620f4240f1600055600051600155 +2a203f69a317afd0cdf2dd1ca84a097da8a0cdda385e87a53540eee36596e3b3=7f6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9600052601b6020527f79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986040527f6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9606052602060006080600060006001620f4240f1600055600051600155 9c3d4d32bdfbe6aba7805fac561682e706c6fe15490dd10a81f815ab1c72ddab=6000600055600060015560006002556000600355600060006000600060016000614e20f100 f3377e9d4f09b635d56a8f2920cb572f927692b5c7d275e0011a9f054139d298=600060005560006001556000600255600060035560006000600060006001600061c350f100 e3669f5ce010826e278e252dec1f74ceb2e71ed12270a062ed4de187ea78e719=635a60fd556000526004601c6000f000 -94dbd8dbb7085e6bcb88b8be8b99cc70470085eb68d1b80dfcb78b8fa9a713a8=6001ff00 21bf113995efc70852a2c4e35595a6f277fa46118386eecd47fa077730ca3cd1=6000600060006000600060006000f1506000ff00 +94dbd8dbb7085e6bcb88b8be8b99cc70470085eb68d1b80dfcb78b8fa9a713a8=6001ff00 9154fb82afafc124f4eb1ba75102f69e51a2957e3b3a6bd4ed421173a1a57a11=6000600060006000600160006000f1506000ff00 82f8a4223d0dc45259ee5caeed7281a789472a29852447a1e2c71cf502603732=6000600060006000600160006155f0f1506000ff00 038c2a3bbbd6ae23c6b7c6aa9f7ce434bd6eb3c54d9d1066c8af7d4d3470ae5c=600060006000600060016000600035f1506000ff00 diff --git a/testool/src/compiler.rs b/testool/src/compiler.rs index 6f88c443a1..1a45162a63 100644 --- a/testool/src/compiler.rs +++ b/testool/src/compiler.rs @@ -3,6 +3,7 @@ use anyhow::{bail, Context, Result}; use eth_types::{bytecode, Bytecode, Bytes, H256}; use keccak256::plain::Keccak; +use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, io::{Read, Write}, @@ -65,6 +66,139 @@ impl Cache { } } +#[derive(Debug, Serialize, Deserialize)] +struct CompilerInput { + language: Language, + settings: CompilerSettings, + sources: HashMap, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "PascalCase")] +enum Language { + Solidity, + Yul, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct CompilerSettings { + optimizer: Optimizer, + output_selection: HashMap>>, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Optimizer { + enabled: bool, + details: HashMap, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Source { + content: String, +} + +impl CompilerInput { + pub fn new_default(language: Language, src: &str) -> Self { + let mut sources = HashMap::new(); + sources.insert( + "stdin".to_string(), + Source { + content: src.to_string(), + }, + ); + CompilerInput { + language, + settings: Default::default(), + sources, + } + } +} + +impl Default for CompilerSettings { + fn default() -> Self { + let mut output_selection = HashMap::new(); + let mut selection = HashMap::new(); + selection.insert("*".to_string(), vec!["evm.bytecode".to_string()]); + output_selection.insert("*".to_string(), selection); + CompilerSettings { + optimizer: Default::default(), + output_selection, + } + } +} + +impl Default for Optimizer { + fn default() -> Self { + let mut details = HashMap::new(); + details.insert("peephole".to_string(), false); + details.insert("inliner".to_string(), false); + details.insert("jumpdestRemover".to_string(), false); + Optimizer { + enabled: false, + details, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct CompilationResult { + contracts: HashMap>, + errors: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Contract { + evm: Evm, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Evm { + bytecode: BytecodeResult, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct BytecodeResult { + object: String, + opcodes: String, + source_map: String, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct CompilationError { + component: String, + error_code: String, + formatted_message: String, + message: String, + severity: Severity, + #[serde(rename = "type")] + error_type: String, + source_location: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +enum Severity { + Error, + Warning, + Info, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct SourceLocation { + end: i32, + file: String, + start: i32, +} + #[derive(Default)] pub struct Compiler { cache: Option, @@ -142,64 +276,42 @@ impl Compiler { /// compiles YUL code pub fn yul(&mut self, src: &str) -> Result { - if let Some(bytecode) = self.cache.as_mut().and_then(|c| c.get(src)) { - return Ok(bytecode.clone()); - } - if !self.compile { - bail!("No way to compile Yul for '{}'", src) - } - - let stdout = Self::exec( - &["run", "-i", "--rm", "solc", "--strict-assembly", "-"], - src, - )?; - let placeholder = "Binary representation:\n"; - let from_pos = stdout.find(placeholder); - let len = from_pos.and_then(|pos| stdout[pos + placeholder.len()..].find('\n')); - let bytecode = if let (Some(from_pos), Some(len)) = (from_pos, len) { - let hex = &stdout[from_pos + placeholder.len()..from_pos + placeholder.len() + len]; - Bytes::from(hex::decode(&hex)?) - } else { - bail!("Unable to compile: {}", src); - }; - if let Some(cache) = &mut self.cache { - cache.insert(src, bytecode.clone())?; - } - - Ok(bytecode) + self.solc(Language::Yul, src) } + /// compiles Solidity code pub fn solidity(&mut self, src: &str) -> Result { + self.solc(Language::Solidity, src) + } + + fn solc(&mut self, language: Language, src: &str) -> Result { if let Some(bytecode) = self.cache.as_mut().and_then(|c| c.get(src)) { return Ok(bytecode.clone()); } if !self.compile { - bail!("No way to compile Solidity for '{}'", src) + bail!("No way to compile {:?} for '{}'", language, src) } + let compiler_input = CompilerInput::new_default(language, src); let stdout = Self::exec( - &[ - "run", - "-i", - "--rm", - "solc", - "--bin", - "--optimize", - "--metadata-hash", - "none", - "-", - ], - src, + &["run", "-i", "--rm", "solc", "--standard-json", "-"], + serde_json::to_string(&compiler_input).unwrap().as_str(), )?; - let placeholder = "Binary:\n"; - let from_pos = stdout.find(placeholder); - let len = from_pos.and_then(|pos| stdout[pos + placeholder.len()..].find('\n')); - let bytecode = if let (Some(from_pos), Some(len)) = (from_pos, len) { - let hex = &stdout[from_pos + placeholder.len()..from_pos + placeholder.len() + len]; - Bytes::from(hex::decode(&hex)?) - } else { - bail!("Unable to compile: {}", src); - }; + let mut compilation_result: CompilationResult = serde_json::from_str(&stdout)?; + let bytecode = compilation_result + .contracts + .remove("stdin") + .expect("should have stdin") + .into_iter() + .next() + .expect("should have one contract") + .1 + .evm + .bytecode + .object; + + let bytecode = Bytes::from(hex::decode(bytecode)?); + if let Some(cache) = &mut self.cache { cache.insert(src, bytecode.clone())?; } From 6b890d53f8ac987462823abb36a7c03bf7033440 Mon Sep 17 00:00:00 2001 From: Richord Date: Thu, 13 Apr 2023 19:49:33 -0700 Subject: [PATCH 008/102] Bytecode soundness patch on last byte (#1333) ### Description Fixes bug soundness in bytecode circuit, where an attacker can insert as many bytes after the last byte (row where `q_last`=1). ### Issue Link https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1332 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - Bug fix 1: Add a constraint that forces the next state to be "Header" when the current state is "Byte" and `index == length - 1` - Bug fix 2: set `q_enable=1` for the row where `q_last=1` ### Rationale This would patch the possibility of an attacker inserting false bytes that extend beyond the correct bytecode. ### How Has This Been Tested? Created a test called `bytecode_soundness_bug_1` that overwrites the last rows with`tag=Byte`. `cargo test --features test --package zkevm-circuits --lib -- bytecode_circuit::circuit::tests::bytecode_soundness_bug_1 --exact --nocapture` Also ran other unit tests to check correctness was maintained. --------- Co-authored-by: Eduard S --- .../src/bytecode_circuit/bytecode_unroller.rs | 2 +- .../src/bytecode_circuit/circuit.rs | 124 +++++++++++++++++- zkevm-circuits/src/bytecode_circuit/test.rs | 34 +++++ 3 files changed, 155 insertions(+), 5 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index e032461a1c..299fa008b7 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -16,7 +16,7 @@ pub(crate) struct BytecodeRow { } /// Unrolled bytecode -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Default)] pub struct UnrolledBytecode { pub(crate) bytes: Vec, pub(crate) rows: Vec>, diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 87ea2351f5..7f131fab06 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -36,6 +36,8 @@ pub struct BytecodeCircuitConfig { push_data_size: Column, push_data_left_inv: Column, push_data_left_is_zero: IsZeroConfig, + index_length_diff_inv: Column, + index_length_diff_is_zero: IsZeroConfig, push_table: [Column; PUSH_TABLE_WIDTH], // External tables pub(crate) keccak_table: KeccakTable, @@ -72,6 +74,7 @@ impl SubCircuitConfig for BytecodeCircuitConfig { let length = meta.advice_column(); let push_data_size = meta.advice_column(); let push_data_left_inv = meta.advice_column(); + let index_length_diff_inv = meta.advice_column(); let push_table = array_init::array_init(|_| meta.fixed_column()); // annotate columns @@ -125,6 +128,17 @@ impl SubCircuitConfig for BytecodeCircuitConfig { push_data_left_inv, ); + let index_length_diff_is_zero = IsZeroChip::configure( + meta, + |meta| meta.query_fixed(q_enable, Rotation::cur()), + |meta| { + meta.query_advice(bytecode_table.index, Rotation::cur()) + 1.expr() + - meta.query_advice(length, Rotation::cur()) + }, + index_length_diff_inv, + ); + // dbg!(index_length_diff_is_zero.clone().is_zero_expression); + // When q_first || q_last -> // assert cur.tag == Header meta.create_gate("first and last row", |meta| { @@ -339,6 +353,23 @@ impl SubCircuitConfig for BytecodeCircuitConfig { ])) }); + // When cur.tag == Byte and cur.index + 1 == cur.length -> + // assert next.tag == Header + meta.create_gate("cur.tag == Byte and cur.index + 1 == cur.length", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + cb.require_zero( + "next.tag == Header", + meta.query_advice(bytecode_table.tag, Rotation::next()), + ); + + cb.gate(and::expr(vec![ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(bytecode_table.tag, Rotation::cur()), + index_length_diff_is_zero.clone().is_zero_expression, + ])) + }); + // When is_byte_to_header -> // assert cur.index + 1 == cur.length // assert keccak256_table_lookup(cur.hash, cur.length, cur.value_rlc) @@ -396,6 +427,8 @@ impl SubCircuitConfig for BytecodeCircuitConfig { push_data_size, push_data_left_inv, push_data_left_is_zero, + index_length_diff_inv, + index_length_diff_is_zero, push_table, keccak_table, } @@ -408,9 +441,10 @@ impl BytecodeCircuitConfig { layouter: &mut impl Layouter, size: usize, witness: &[UnrolledBytecode], + overwrite: &UnrolledBytecode, challenges: &Challenges>, ) -> Result<(), Error> { - self.assign_internal(layouter, size, witness, challenges, true) + self.assign_internal(layouter, size, witness, overwrite, challenges, true) } pub(crate) fn assign_internal( @@ -418,11 +452,14 @@ impl BytecodeCircuitConfig { layouter: &mut impl Layouter, size: usize, witness: &[UnrolledBytecode], + overwrite: &UnrolledBytecode, challenges: &Challenges>, fail_fast: bool, ) -> Result<(), Error> { let push_data_left_is_zero_chip = IsZeroChip::construct(self.push_data_left_is_zero.clone()); + let index_length_diff_is_zero_chip = + IsZeroChip::construct(self.index_length_diff_is_zero.clone()); // Subtract the unusable rows from the size assert!(size > self.minimum_rows); @@ -452,6 +489,7 @@ impl BytecodeCircuitConfig { bytecode, challenges, &push_data_left_is_zero_chip, + &index_length_diff_is_zero_chip, empty_hash, &mut offset, last_row_offset, @@ -464,11 +502,58 @@ impl BytecodeCircuitConfig { self.set_padding_row( &mut region, &push_data_left_is_zero_chip, + &index_length_diff_is_zero_chip, empty_hash, idx, last_row_offset, )?; } + + // Overwrite the witness assignment by using the values in the `overwrite` + // parameter. This is used to explicitly set intermediate witness values for + // negative tests. + let mut value_rlc = challenges.keccak_input().map(|_| F::zero()); + for (offset, row) in overwrite.rows.iter().enumerate() { + for (name, column, value) in [ + ("tag", self.bytecode_table.tag, row.tag), + ("index", self.bytecode_table.index, row.index), + ("is_code", self.bytecode_table.is_code, row.is_code), + ("value", self.bytecode_table.value, row.value), + ("length", self.length, F::from(overwrite.bytes.len() as u64)), + ] { + region.assign_advice( + || format!("assign {} {}", name, offset), + column, + offset, + || Value::known(value), + )?; + } + + if row.tag == F::one() { + value_rlc.as_mut().zip(challenges.keccak_input()).map( + |(value_rlc, challenge)| { + *value_rlc = *value_rlc * challenge + row.value + }, + ); + } else { + value_rlc = challenges.keccak_input().map(|_| F::zero()); + } + + let code_hash = challenges + .evm_word() + .map(|challenge| rlc::value(&row.code_hash.to_le_bytes(), challenge)); + for (name, column, value) in [ + ("code_hash", self.bytecode_table.code_hash, code_hash), + ("value_rlc", self.value_rlc, value_rlc), + ] { + region.assign_advice( + || format!("assign {} {}", name, offset), + column, + offset, + || value, + )?; + } + } Ok(()) }, ) @@ -481,6 +566,7 @@ impl BytecodeCircuitConfig { bytecode: &UnrolledBytecode, challenges: &Challenges>, push_data_left_is_zero_chip: &IsZeroChip, + index_length_diff_is_zero_chip: &IsZeroChip, empty_hash: Value, offset: &mut usize, last_row_offset: usize, @@ -533,6 +619,7 @@ impl BytecodeCircuitConfig { self.set_row( region, push_data_left_is_zero_chip, + index_length_diff_is_zero_chip, *offset, true, *offset == last_row_offset, @@ -569,6 +656,7 @@ impl BytecodeCircuitConfig { self.set_padding_row( region, push_data_left_is_zero_chip, + index_length_diff_is_zero_chip, empty_hash, *offset, last_row_offset, @@ -583,6 +671,7 @@ impl BytecodeCircuitConfig { &self, region: &mut Region<'_, F>, push_data_left_is_zero_chip: &IsZeroChip, + index_length_diff_is_zero_chip: &IsZeroChip, empty_hash: Value, offset: usize, last_row_offset: usize, @@ -590,8 +679,9 @@ impl BytecodeCircuitConfig { self.set_row( region, push_data_left_is_zero_chip, + index_length_diff_is_zero_chip, offset, - offset < last_row_offset, + offset <= last_row_offset, offset == last_row_offset, empty_hash, F::from(BytecodeFieldTag::Header as u64), @@ -610,6 +700,7 @@ impl BytecodeCircuitConfig { &self, region: &mut Region<'_, F>, push_data_left_is_zero_chip: &IsZeroChip, + index_length_diff_is_zero_chip: &IsZeroChip, offset: usize, enable: bool, last: bool, @@ -687,6 +778,12 @@ impl BytecodeCircuitConfig { Value::known(F::from(push_data_left)), )?; + index_length_diff_is_zero_chip.assign( + region, + offset, + Value::known(index + F::one() - length), + )?; + Ok(()) } @@ -696,6 +793,8 @@ impl BytecodeCircuitConfig { self.push_data_left_is_zero .annotate_columns_in_region(region, "BYTECODE"); + self.index_length_diff_is_zero + .annotate_columns_in_region(region, "BYTECODE"); region.name_column(|| "BYTECODE_q_enable", self.q_enable); region.name_column(|| "BYTECODE_q_first", self.q_first); region.name_column(|| "BYTECODE_q_last", self.q_last); @@ -704,6 +803,10 @@ impl BytecodeCircuitConfig { region.name_column(|| "BYTECODE_push_data_size", self.push_data_size); region.name_column(|| "BYTECODE_value_rlc", self.value_rlc); region.name_column(|| "BYTECODE_push_data_left_inv", self.push_data_left_inv); + region.name_column( + || "BYTECODE_index_length_diff_inv", + self.index_length_diff_inv, + ); } /// load fixed tables @@ -744,12 +847,18 @@ pub struct BytecodeCircuit { pub bytecodes: Vec>, /// Circuit size pub size: usize, + /// Overwrite + pub overwrite: UnrolledBytecode, } impl BytecodeCircuit { /// new BytecodeCircuitTester pub fn new(bytecodes: Vec>, size: usize) -> Self { - BytecodeCircuit { bytecodes, size } + BytecodeCircuit { + bytecodes, + size, + overwrite: Default::default(), + } } /// Creates bytecode circuit from block and bytecode_size. @@ -798,6 +907,13 @@ impl SubCircuit for BytecodeCircuit { layouter: &mut impl Layouter, ) -> Result<(), Error> { config.load_aux_tables(layouter)?; - config.assign_internal(layouter, self.size, &self.bytecodes, challenges, false) + config.assign_internal( + layouter, + self.size, + &self.bytecodes, + &self.overwrite, + challenges, + false, + ) } } diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 85ec8f80df..6d27db90a4 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -281,3 +281,37 @@ fn bytecode_invalid_is_code() { test_bytecode_circuit_unrolled::(k, vec![invalid], false); } } + +#[test] +#[should_panic] +#[allow(clippy::clone_on_copy)] +fn bytecode_soundness_bug_1() { + let k = 9; + let bytecode = vec![1, 2, 3, 4]; + let bytecode_len = bytecode.len(); + let unrolled = unroll(bytecode); + let unrolled_len = unrolled.rows.len(); + let code_hash = unrolled.rows[0].code_hash.clone(); + let mut index = bytecode_len as u64; + let size = 100; + let minimum_rows = 8; + + let mut overwrite = unrolled.clone(); + for i in 0..size - minimum_rows + 3 { + if i >= unrolled_len { + overwrite.rows.push(BytecodeRow { + code_hash: code_hash.clone(), + tag: Fr::one(), + index: Fr::from(index), + is_code: Fr::one(), + value: Fr::from((i % 10 + 1) as u64), + }); + index += 1; + } + } + let mut circuit = BytecodeCircuit::::new(vec![unrolled], size); + circuit.overwrite = overwrite; + + let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); + prover.assert_satisfied_par(); +} From c88d82dfe3d3a3c8003853d595f2254c5c00c029 Mon Sep 17 00:00:00 2001 From: Han Date: Fri, 14 Apr 2023 19:28:53 +0800 Subject: [PATCH 009/102] Fix `ExecutionState::halts_in_exception` (#1299) ### Description This PR aims to remove `ExecutionState::{ErrorDepth,InsufficientBalance ,ErrorContractAddressCollision}` from `ExecutionState::halts_in_exception` and handle `InsufficientBalance` properly by `CallOpGadget` ### Issue Link https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1298 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents Some exception states happen right in the moment when we are doing `*CALL*` or `CREATE*`, including: - `ErrorDepth` - `ErrorInsufficientBalance` - `ErrorContractAddressCollision` Which will only be treated as failure of sub-call, and won't halt current call. ```mermaid stateDiagram-v2 state fork <> state join <> state NextCall { ...* --> join } state CurrentCall { ... --> fork fork --> CALL|CREATE fork --> ErrorDepth fork --> ErrorInsufficientBalance fork --> ErrorContractAddressCollision CALL|CREATE --> NextCall ErrorDepth --> join ErrorInsufficientBalance --> join ErrorContractAddressCollision --> join join --> NextStep } ``` However, if we want to handle these as a separate state we'd have many constraint duplicated (e.g. gas cost calculation), so `ErrorInsufficientBalance` is merged into `CALL` in https://github.com/privacy-scaling-explorations/zkevm-circuits/pull/998 without too much overhead. For the other 2 states we could apply the same strategy to avoid confusion. ### Rationale ### How Has This Been Tested? ### Design choices --- zkevm-circuits/src/evm_circuit/execution.rs | 5 +---- zkevm-circuits/src/evm_circuit/step.rs | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index bc0d47e001..83ac420dcc 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -299,8 +299,6 @@ pub(crate) struct ExecutionConfig { error_oog_self_destruct: Box>, error_oog_code_store: Box>, - error_insufficient_balance: - Box>, error_invalid_jump: Box>, error_invalid_opcode: Box>, error_depth: Box>, @@ -563,7 +561,6 @@ impl ExecutionConfig { error_oog_create2: configure_gadget!(), error_oog_self_destruct: configure_gadget!(), error_oog_code_store: configure_gadget!(), - error_insufficient_balance: configure_gadget!(), error_invalid_jump: configure_gadget!(), error_invalid_opcode: configure_gadget!(), error_write_protection: configure_gadget!(), @@ -1280,7 +1277,7 @@ impl ExecutionConfig { } ExecutionState::ErrorInsufficientBalance => { - assign_exec_step!(self.error_insufficient_balance) + assign_exec_step!(self.call_op_gadget) } ExecutionState::ErrorInvalidJump => { assign_exec_step!(self.error_invalid_jump) diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index a41c1758d4..9658b871bb 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -137,9 +137,6 @@ impl ExecutionState { Self::ErrorInvalidOpcode | Self::ErrorStack | Self::ErrorWriteProtection - | Self::ErrorDepth - | Self::ErrorInsufficientBalance - | Self::ErrorContractAddressCollision | Self::ErrorInvalidCreationCode | Self::ErrorMaxCodeSizeExceeded | Self::ErrorInvalidJump From 3aa36a2ca9360723a5eb87816a6b02655598d2d5 Mon Sep 17 00:00:00 2001 From: Vu Date: Mon, 17 Apr 2023 21:58:22 +0700 Subject: [PATCH 010/102] create tx by mock crate (#1360) ### Description Fix issue #1192 ### Issue Link Issue #1192 ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - [_item_] ### Rationale [_design decisions and extended information_] ### How Has This Been Tested? [_explanation_]
## How to fill a PR description Please give a concise description of your PR. The target readers could be future developers, reviewers, and auditors. By reading your description, they should easily understand the changes proposed in this pull request. MUST: Reference the issue to resolve ### Single responsability Is RECOMMENDED to create single responsibility commits, but not mandatory. Anyway, you MUST enumerate the changes in a unitary way, e.g. ``` This PR contains: - Cleanup of xxxx, yyyy - Changed xxxx to yyyy in order to bla bla - Added xxxx function to ... - Refactored .... ``` ### Design choices RECOMMENDED to: - What types of design choices did you face? - What decisions you have made? - Any valuable information that could help reviewers to think critically --- .../src/evm_circuit/execution/begin_tx.rs | 25 +++++++++++-------- .../execution/error_oog_constant.rs | 23 +++++++++-------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index aa93f2b55e..d9e2dee456 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -563,11 +563,13 @@ impl ExecutionGadget for BeginTxGadget { #[cfg(test)] mod test { + use std::vec; + use crate::{evm_circuit::test::rand_bytes, test_util::CircuitTestBuilder}; use bus_mapping::evm::OpcodeId; use eth_types::{self, bytecode, evm_types::GasCost, word, Bytecode, Word}; - use mock::{eth, gwei, TestContext, MOCK_ACCOUNTS}; + use mock::{eth, gwei, MockTransaction, TestContext, MOCK_ACCOUNTS}; fn gas(call_data: &[u8]) -> Word { Word::from( @@ -623,19 +625,20 @@ mod test { CircuitTestBuilder::new_from_test_ctx(ctx).run(); } - // TODO: Use `mock` crate. fn mock_tx(value: Word, gas_price: Word, calldata: Vec) -> eth_types::Transaction { let from = MOCK_ACCOUNTS[1]; let to = MOCK_ACCOUNTS[0]; - eth_types::Transaction { - from, - to: Some(to), - value, - gas: gas(&calldata), - gas_price: Some(gas_price), - input: calldata.into(), - ..Default::default() - } + + let mock_transaction = MockTransaction::default() + .from(from) + .to(to) + .value(value) + .gas(gas(&calldata)) + .gas_price(gas_price) + .input(calldata.into()) + .build(); + + eth_types::Transaction::from(mock_transaction) } #[test] diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs index bc389a3114..717c91505c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs @@ -96,7 +96,8 @@ mod test { }; use mock::{ - eth, gwei, test_ctx::helpers::account_0_code_account_1_no_code, TestContext, MOCK_ACCOUNTS, + eth, gwei, test_ctx::helpers::account_0_code_account_1_no_code, MockTransaction, + TestContext, MOCK_ACCOUNTS, }; fn gas(call_data: &[u8]) -> Word { @@ -144,19 +145,19 @@ mod test { CircuitTestBuilder::new_from_test_ctx(ctx).run(); } - // TODO: Use `mock` crate fn mock_tx(value: Word, gas_price: Word, calldata: Vec) -> eth_types::Transaction { let from = MOCK_ACCOUNTS[1]; let to = MOCK_ACCOUNTS[0]; - eth_types::Transaction { - from, - to: Some(to), - value, - gas: gas(&calldata), - gas_price: Some(gas_price), - input: calldata.into(), - ..Default::default() - } + + let mock_transaction = MockTransaction::default() + .from(from) + .to(to) + .value(value) + .gas(gas(&calldata)) + .gas_price(gas_price) + .input(calldata.into()) + .build(); + eth_types::Transaction::from(mock_transaction) } #[test] From 3429f83bd43a8da32e8b588f866432a6eee8b489 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 18 Apr 2023 20:10:26 +0200 Subject: [PATCH 011/102] Update geth dependency from v1.10.18 to v1.11.5 (#1363) ### Description Updates the geth dependency in geth-utils to latest release. Pulled this out from #1361. ### Issue Link Related to #1362. ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - Update geth dependency (and ran `go mod tidy` to update sub-dependencies) - Update code bindings to struct changes ### Rationale N/A ### How Has This Been Tested? Using the testing suite in the repo. --- .github/workflows/ci.yml | 2 +- .github/workflows/integration.yml | 2 +- geth-utils/gethutil/trace.go | 36 +- geth-utils/go.mod | 2 +- geth-utils/go.sum | 855 ++++++++++++++++++++++++++- integration-tests/docker-compose.yml | 2 +- 6 files changed, 853 insertions(+), 46 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf354642cb..0887779a97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,7 @@ jobs: - name: Setup golang uses: actions/setup-go@v3 with: - go-version: ~1.18 + go-version: ~1.19 # Go cache for building geth-utils - name: Go cache uses: actions/cache@v3 diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 777407ab11..6839d3cb76 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -61,7 +61,7 @@ jobs: - name: Setup golang uses: actions/setup-go@v3 with: - go-version: ~1.18 + go-version: ~1.19 # Go cache for building geth-utils - name: Go cache uses: actions/cache@v3 diff --git a/geth-utils/gethutil/trace.go b/geth-utils/gethutil/trace.go index 56cf94dbbf..744ce01d40 100644 --- a/geth-utils/gethutil/trace.go +++ b/geth-utils/gethutil/trace.go @@ -124,6 +124,8 @@ type TraceConfig struct { LoggerConfig *logger.Config `json:"logger_config"` } +func newUint64(val uint64) *uint64 { return &val } + func Trace(config TraceConfig) ([]*ExecutionResult, error) { chainConfig := params.ChainConfig{ ChainID: toBigInt(config.ChainID), @@ -145,7 +147,7 @@ func Trace(config TraceConfig) ([]*ExecutionResult, error) { var txsGasLimit uint64 blockGasLimit := toBigInt(config.Block.GasLimit).Uint64() - messages := make([]types.Message, len(config.Transactions)) + messages := make([]core.Message, len(config.Transactions)) for i, tx := range config.Transactions { // If gas price is specified directly, the tx is treated as legacy type. if tx.GasPrice != nil { @@ -158,19 +160,19 @@ func Trace(config TraceConfig) ([]*ExecutionResult, error) { txAccessList[i].Address = accessList.Address txAccessList[i].StorageKeys = accessList.StorageKeys } - messages[i] = types.NewMessage( - tx.From, - tx.To, - uint64(tx.Nonce), - toBigInt(tx.Value), - uint64(tx.GasLimit), - toBigInt(tx.GasPrice), - toBigInt(tx.GasFeeCap), - toBigInt(tx.GasTipCap), - tx.CallData, - txAccessList, - false, - ) + messages[i] = core.Message{ + From: tx.From, + To: tx.To, + Nonce: uint64(tx.Nonce), + Value: toBigInt(tx.Value), + GasLimit: uint64(tx.GasLimit), + GasPrice: toBigInt(tx.GasPrice), + GasFeeCap: toBigInt(tx.GasFeeCap), + GasTipCap: toBigInt(tx.GasTipCap), + Data: tx.CallData, + AccessList: txAccessList, + SkipAccountChecks: false, + } txsGasLimit += uint64(tx.GasLimit) } @@ -191,7 +193,7 @@ func Trace(config TraceConfig) ([]*ExecutionResult, error) { }, Coinbase: config.Block.Coinbase, BlockNumber: toBigInt(config.Block.Number), - Time: toBigInt(config.Block.Timestamp), + Time: toBigInt(config.Block.Timestamp).Uint64(), Difficulty: toBigInt(config.Block.Difficulty), BaseFee: toBigInt(config.Block.BaseFee), GasLimit: blockGasLimit, @@ -215,9 +217,9 @@ func Trace(config TraceConfig) ([]*ExecutionResult, error) { executionResults := make([]*ExecutionResult, len(config.Transactions)) for i, message := range messages { tracer := logger.NewStructLogger(config.LoggerConfig) - evm := vm.NewEVM(blockCtx, core.NewEVMTxContext(message), stateDB, &chainConfig, vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) + evm := vm.NewEVM(blockCtx, core.NewEVMTxContext(&message), stateDB, &chainConfig, vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) - result, err := core.ApplyMessage(evm, message, new(core.GasPool).AddGas(message.Gas())) + result, err := core.ApplyMessage(evm, &message, new(core.GasPool).AddGas(message.GasLimit)) if err != nil { return nil, fmt.Errorf("Failed to apply config.Transactions[%d]: %w", i, err) } diff --git a/geth-utils/go.mod b/geth-utils/go.mod index d1c9cd7465..2892aa855f 100644 --- a/geth-utils/go.mod +++ b/geth-utils/go.mod @@ -3,7 +3,7 @@ module main go 1.16 require ( - github.com/ethereum/go-ethereum v1.10.18 + github.com/ethereum/go-ethereum v1.11.5 github.com/holiman/uint256 v1.2.0 ) diff --git a/geth-utils/go.sum b/geth-utils/go.sum index 31cc98766a..62c668a662 100644 --- a/geth-utils/go.sum +++ b/geth-utils/go.sum @@ -8,34 +8,84 @@ cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTj cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= +github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= +github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= +github.com/CloudyKit/jet/v6 v6.1.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= +github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo= @@ -45,8 +95,15 @@ github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7 github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= @@ -58,16 +115,54 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= +github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= +github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= +github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= +github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= +github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= +github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= +github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= +github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= @@ -76,85 +171,176 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= +github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= +github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/go-ethereum v1.10.18 h1:hLEd5M+UD0GJWPaROiYMRgZXl6bi5YwoTJSthsx5CZw= -github.com/ethereum/go-ethereum v1.10.18/go.mod h1:RD3NhcSBjZpj3k+SnQq24wBrmnmie78P5R/P62iNBD8= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= +github.com/ethereum/go-ethereum v1.11.5 h1:3M1uan+LAUvdn+7wCEFrcMM4LJTeuxDrPTg/f31a5QQ= +github.com/ethereum/go-ethereum v1.11.5/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= +github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732/go.mod h1:o/XfIXWi4/GqbQirfRm5uTbXMG5NpqxkxblnbZ+QM9I= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= +github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= +github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= @@ -163,26 +349,80 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= @@ -190,7 +430,11 @@ github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= +github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= @@ -203,167 +447,450 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= +github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= +github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/httpexpect/v2 v2.3.1/go.mod h1:ICTf89VBKSD3KB0fsyyHviKF8G8hyepP0dOXJPWz3T0= +github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= +github.com/iris-contrib/jade v1.1.4/go.mod h1:EDqR+ur9piDl6DUgs6qRrlfzmlx/D5UybogqrXvJTBE= +github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= +github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= +github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kataras/blocks v0.0.6/go.mod h1:UK+Iwk0Oxpc0GdoJja7sEildotAUKK1LYeYcVF0COWc= +github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I= +github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= +github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= +github.com/kataras/golog v0.1.7/go.mod h1:jOSQ+C5fUqsNSwurB/oAHq1IFSb0KI3l6GMa7xB6dZA= +github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= +github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= +github.com/kataras/iris/v12 v12.2.0-beta5/go.mod h1:q26aoWJ0Knx/00iPKg5iizDK7oQQSPjbD8np0XDh6dc= +github.com/kataras/jwt v0.1.8/go.mod h1:Q5j2IkcIHnfwy+oNY3TVWuEBJNw0ADgCcXK9CaZwV4o= +github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= +github.com/kataras/neffos v0.0.20/go.mod h1:srdvC/Uo8mgrApWW0AYtiiLgMbyNPf69qPsd2FhE6MQ= +github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= +github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= +github.com/kataras/pio v0.0.10/go.mod h1:gS3ui9xSD+lAUpbYnjOGiQyY7sUMJO+EHpiRzhtZ5no= +github.com/kataras/pio v0.0.11/go.mod h1:38hH6SWH6m4DKSYmRhlrCJ5WItwWgCVrTNU62XZyUvI= +github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= +github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4= +github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= +github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= +github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= +github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailgun/raymond/v2 v2.0.46/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= +github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= +github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= +github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= +github.com/mediocregopher/radix/v3 v3.8.0/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= +github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= +github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= +github.com/nats-io/jwt/v2 v2.3.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= +github.com/nats-io/nats-server/v2 v2.8.4/go.mod h1:8zZa+Al3WsESfmgSs98Fi06dRWLH5Bnq90m5bKD/eT4= +github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nats.go v1.15.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nats.go v1.16.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= +github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI= +github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tdewolff/minify/v2 v2.12.1/go.mod h1:p5pwbvNs1ghbFED/ZW1towGsnnWwzvM8iz8l0eURi9g= +github.com/tdewolff/minify/v2 v2.12.4/go.mod h1:h+SRvSIX3kwgwTFOpSckvSxgax3uy8kZTSF1Ojrr3bk= +github.com/tdewolff/parse/v2 v2.6.3/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= +github.com/tdewolff/parse/v2 v2.6.4/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= +github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= -github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= +github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= +github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= +github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= +github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= +github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -374,7 +901,13 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= +golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -386,96 +919,229 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -483,21 +1149,31 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -508,24 +1184,58 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191126055441-b0650ceb63d9/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= @@ -536,11 +1246,29 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -555,44 +1283,121 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/integration-tests/docker-compose.yml b/integration-tests/docker-compose.yml index a1765c6561..f3a5dc75ff 100644 --- a/integration-tests/docker-compose.yml +++ b/integration-tests/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: geth0: - image: "ethereum/client-go:v1.10.18" + image: "ethereum/client-go:v1.11.5" container_name: zkevm-geth0 ports: - 8545:8545 From e55ba06f1e5cba9602614788a026c59ac41e73a8 Mon Sep 17 00:00:00 2001 From: Steven Date: Thu, 20 Apr 2023 20:09:52 +0800 Subject: [PATCH 012/102] Implement circuit for `ErrorOutOfGasMemoryCopy` state (#1288) ### Description Spec Markdown PR https://github.com/privacy-scaling-explorations/zkevm-specs/pull/397 #### Summary 1. Merge OOG error `ExtCodeCopy` into `MemoryCopy`. 2. Implement bus-mapping and circuit for this OOG error of `CALLDATACOPY`, `CODECOPY`, `EXTCODECOPY` and `RETURNDATACOPY` opcodes. 3. OOG error executions of `CALLDATACOPY`, `CODECOPY` and `RETURNDATACOPY` are same. 4. `EXTCODECOPY` has extra `1` stack pop, and constant gas costs are different for cold (2600) and warm (100) accounts according to EIP-2929 (could reference [go-etherum gasExtCodeCopyEIP2929 function](https://github.com/ethereum/go-ethereum/blob/master/core/vm/operations_acl.go#L116)). 5. Fix `memory_copier_gas_cost` function to not calculate memory expansion for zero copy size in gas utils of `eth-types`. ### Issue Link Close https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1266 ### Type of change - [X] New feature (non-breaking change which adds functionality) ### How Has This Been Tested? Add new unit-test cases for this error state. --- bus-mapping/src/error.rs | 14 +- bus-mapping/src/evm/opcodes.rs | 3 + .../src/evm/opcodes/error_oog_memory_copy.rs | 73 ++++ eth-types/src/evm_types/gas_utils.rs | 10 +- zkevm-circuits/src/evm_circuit/execution.rs | 4 +- .../execution/error_oog_memory_copy.rs | 406 ++++++++++++++++++ zkevm-circuits/src/witness/step.rs | 1 - 7 files changed, 499 insertions(+), 12 deletions(-) create mode 100644 bus-mapping/src/evm/opcodes/error_oog_memory_copy.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs diff --git a/bus-mapping/src/error.rs b/bus-mapping/src/error.rs index 8fe916ce33..0c9914c1e3 100644 --- a/bus-mapping/src/error.rs +++ b/bus-mapping/src/error.rs @@ -73,8 +73,8 @@ pub enum OogError { /// Out of Gas for CREATE, RETURN, REVERT, which have dynamic memory /// expansion gas cost DynamicMemoryExpansion, - /// Out of Gas for CALLDATACOPY, CODECOPY, RETURNDATACOPY, which copy a - /// specified chunk of memory + /// Out of Gas for CALLDATACOPY, CODECOPY, EXTCODECOPY, RETURNDATACOPY, + /// which copy a specified chunk of memory MemoryCopy, /// Out of Gas for BALANCE, EXTCODESIZE, EXTCODEHASH, which possibly touch /// an extra account @@ -88,8 +88,6 @@ pub enum OogError { Exp, /// Out of Gas for SHA3 Sha3, - /// Out of Gas for EXTCODECOPY - ExtCodeCopy, /// Out of Gas for SLOAD and SSTORE SloadSstore, /// Out of Gas for CALL, CALLCODE, DELEGATECALL and STATICCALL @@ -144,9 +142,10 @@ pub(crate) fn get_step_reported_error(op: &OpcodeId, error: &str) -> ExecError { OpcodeId::CREATE | OpcodeId::RETURN | OpcodeId::REVERT => { OogError::DynamicMemoryExpansion } - OpcodeId::CALLDATACOPY | OpcodeId::CODECOPY | OpcodeId::RETURNDATACOPY => { - OogError::MemoryCopy - } + OpcodeId::CALLDATACOPY + | OpcodeId::CODECOPY + | OpcodeId::EXTCODECOPY + | OpcodeId::RETURNDATACOPY => OogError::MemoryCopy, OpcodeId::BALANCE | OpcodeId::EXTCODESIZE | OpcodeId::EXTCODEHASH => { OogError::AccountAccess } @@ -155,7 +154,6 @@ pub(crate) fn get_step_reported_error(op: &OpcodeId, error: &str) -> ExecError { } OpcodeId::EXP => OogError::Exp, OpcodeId::SHA3 => OogError::Sha3, - OpcodeId::EXTCODECOPY => OogError::ExtCodeCopy, OpcodeId::CALL | OpcodeId::CALLCODE | OpcodeId::DELEGATECALL | OpcodeId::STATICCALL => { OogError::Call } diff --git a/bus-mapping/src/evm/opcodes.rs b/bus-mapping/src/evm/opcodes.rs index 8e558fb189..076a64ef0b 100644 --- a/bus-mapping/src/evm/opcodes.rs +++ b/bus-mapping/src/evm/opcodes.rs @@ -58,6 +58,7 @@ mod error_invalid_jump; mod error_oog_call; mod error_oog_exp; mod error_oog_log; +mod error_oog_memory_copy; mod error_oog_sload_sstore; mod error_return_data_outofbound; mod error_simple; @@ -83,6 +84,7 @@ use error_invalid_jump::InvalidJump; use error_oog_call::OOGCall; use error_oog_exp::OOGExp; use error_oog_log::ErrorOOGLog; +use error_oog_memory_copy::OOGMemoryCopy; use error_oog_sload_sstore::OOGSloadSstore; use error_return_data_outofbound::ErrorReturnDataOutOfBound; use error_simple::ErrorSimple; @@ -275,6 +277,7 @@ fn fn_gen_error_state_associated_ops(error: &ExecError) -> Option Some(ErrorSimple::gen_associated_ops), ExecError::OutOfGas(OogError::Exp) => Some(OOGExp::gen_associated_ops), ExecError::OutOfGas(OogError::Log) => Some(ErrorOOGLog::gen_associated_ops), + ExecError::OutOfGas(OogError::MemoryCopy) => Some(OOGMemoryCopy::gen_associated_ops), ExecError::OutOfGas(OogError::SloadSstore) => Some(OOGSloadSstore::gen_associated_ops), ExecError::StackOverflow => Some(ErrorSimple::gen_associated_ops), ExecError::StackUnderflow => Some(ErrorSimple::gen_associated_ops), diff --git a/bus-mapping/src/evm/opcodes/error_oog_memory_copy.rs b/bus-mapping/src/evm/opcodes/error_oog_memory_copy.rs new file mode 100644 index 0000000000..b334414231 --- /dev/null +++ b/bus-mapping/src/evm/opcodes/error_oog_memory_copy.rs @@ -0,0 +1,73 @@ +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + error::{ExecError, OogError}, + evm::Opcode, + operation::{CallContextField, TxAccessListAccountOp, RW}, + Error, +}; +use eth_types::{evm_types::OpcodeId, GethExecStep, ToAddress}; + +/// Placeholder structure used to implement [`Opcode`] trait over it +/// corresponding to the +/// [`OogError::MemoryCopy`](crate::error::OogError::MemoryCopy). +#[derive(Clone, Copy, Debug)] +pub(crate) struct OOGMemoryCopy; + +impl Opcode for OOGMemoryCopy { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + debug_assert!([ + OpcodeId::CALLDATACOPY, + OpcodeId::CODECOPY, + OpcodeId::EXTCODECOPY, + OpcodeId::RETURNDATACOPY + ] + .contains(&geth_step.op)); + + let mut exec_step = state.new_step(geth_step)?; + exec_step.error = Some(ExecError::OutOfGas(OogError::MemoryCopy)); + + let is_extcodecopy = geth_step.op == OpcodeId::EXTCODECOPY; + + // According to EIP-2929, EXTCODECOPY constant gas cost is different for cold + // and warm accounts. + if is_extcodecopy { + state.call_context_read( + &mut exec_step, + state.call()?.call_id, + CallContextField::TxId, + state.tx_ctx.id().into(), + ); + + let external_address = geth_step.stack.last()?.to_address(); + let is_warm = state.sdb.check_account_in_access_list(&external_address); + state.push_op( + &mut exec_step, + RW::READ, + TxAccessListAccountOp { + tx_id: state.tx_ctx.id(), + address: external_address, + is_warm, + is_warm_prev: is_warm, + }, + ); + } + + // Each of CALLDATACOPY, CODECOPY and RETURNDATACOPY has 3 stack read values. + // But EXTCODECOPY has 4. It has an extra stack pop for external address. + let stack_read_num = if is_extcodecopy { 4 } else { 3 }; + for i in 0..stack_read_num { + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(i), + geth_step.stack.nth_last(i)?, + )?; + } + + state.handle_return(&mut exec_step, geth_steps, true)?; + Ok(vec![exec_step]) + } +} diff --git a/eth-types/src/evm_types/gas_utils.rs b/eth-types/src/evm_types/gas_utils.rs index d1e032d669..8d34a37e20 100644 --- a/eth-types/src/evm_types/gas_utils.rs +++ b/eth-types/src/evm_types/gas_utils.rs @@ -24,8 +24,14 @@ pub fn memory_copier_gas_cost( num_copy_bytes: u64, ) -> u64 { let num_words = (num_copy_bytes + 31) / 32; - num_words * GasCost::COPY.as_u64() - + memory_expansion_gas_cost(curr_memory_word_size, next_memory_word_size) + num_words * GasCost::COPY.as_u64() + + // Note that opcodes with a byte size parameter of 0 will not trigger + // memory expansion, regardless of their offset parameters. + if num_words > 0 { + memory_expansion_gas_cost(curr_memory_word_size, next_memory_word_size) + } else { + 0 + } } /// Calculate EIP 150 gas passed to callee. diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 83ac420dcc..ff44ee7e5a 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -66,6 +66,7 @@ mod error_oog_call; mod error_oog_constant; mod error_oog_exp; mod error_oog_log; +mod error_oog_memory_copy; mod error_oog_sload_sstore; mod error_oog_static_memory; mod error_return_data_oo_bound; @@ -137,6 +138,7 @@ use error_oog_call::ErrorOOGCallGadget; use error_oog_constant::ErrorOOGConstantGadget; use error_oog_exp::ErrorOOGExpGadget; use error_oog_log::ErrorOOGLogGadget; +use error_oog_memory_copy::ErrorOOGMemoryCopyGadget; use error_oog_sload_sstore::ErrorOOGSloadSstoreGadget; use error_return_data_oo_bound::ErrorReturnDataOutOfBoundGadget; use error_stack::ErrorStackGadget; @@ -282,6 +284,7 @@ pub(crate) struct ExecutionConfig { error_oog_call: Box>, error_oog_constant: Box>, error_oog_exp: Box>, + error_oog_memory_copy: Box>, error_oog_sload_sstore: Box>, error_oog_static_memory_gadget: Box>, @@ -290,7 +293,6 @@ pub(crate) struct ExecutionConfig { error_oog_dynamic_memory_gadget: Box>, error_oog_log: Box>, - error_oog_memory_copy: Box>, error_oog_account_access: Box>, error_oog_sha3: Box>, diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs new file mode 100644 index 0000000000..d4f56ba227 --- /dev/null +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs @@ -0,0 +1,406 @@ +use crate::{ + evm_circuit::{ + execution::ExecutionGadget, + param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE}, + step::ExecutionState, + util::{ + common_gadget::CommonErrorGadget, + constraint_builder::ConstraintBuilder, + from_bytes, + math_gadget::{IsZeroGadget, LtGadget}, + memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, + select, CachedRegion, Cell, Word, + }, + witness::{Block, Call, ExecStep, Transaction}, + }, + table::CallContextFieldTag, + util::Expr, +}; +use eth_types::{ + evm_types::{GasCost, OpcodeId}, + Field, ToLittleEndian, U256, +}; +use halo2_proofs::{circuit::Value, plonk::Error}; + +/// Gadget to implement the corresponding out of gas errors for +/// [`OpcodeId::CALLDATACOPY`], [`OpcodeId::CODECOPY`], +/// [`OpcodeId::EXTCODECOPY`] and [`OpcodeId::RETURNDATACOPY`]. +#[derive(Clone, Debug)] +pub(crate) struct ErrorOOGMemoryCopyGadget { + opcode: Cell, + /// Check if `EXTCODECOPY` external address is warm + is_warm: Cell, + tx_id: Cell, + /// Extra stack pop for `EXTCODECOPY` + external_address: Word, + /// Source offset + src_offset: Word, + /// Destination offset and size to copy + dst_memory_addr: MemoryAddressGadget, + memory_expansion: MemoryExpansionGadget, + memory_copier_gas: MemoryCopierGasGadget, + insufficient_gas: LtGadget, + is_extcodecopy: IsZeroGadget, + common_error_gadget: CommonErrorGadget, +} + +impl ExecutionGadget for ErrorOOGMemoryCopyGadget { + const NAME: &'static str = "ErrorOutOfGasMemoryCopy"; + + const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasMemoryCopy; + + fn configure(cb: &mut ConstraintBuilder) -> Self { + let opcode = cb.query_cell(); + cb.require_in_set( + "ErrorOutOfGasMemoryCopy opcode must be CALLDATACOPY, CODECOPY, EXTCODECOPY or RETURNDATACOPY", + opcode.expr(), + vec![ + OpcodeId::CALLDATACOPY.expr(), + OpcodeId::CODECOPY.expr(), + OpcodeId::EXTCODECOPY.expr(), + OpcodeId::RETURNDATACOPY.expr(), + ], + ); + + let dst_offset = cb.query_cell_phase2(); + let src_offset = cb.query_word_rlc(); + let copy_size = cb.query_word_rlc(); + let external_address = cb.query_word_rlc(); + let is_warm = cb.query_bool(); + let tx_id = cb.query_cell(); + + let is_extcodecopy = + IsZeroGadget::construct(cb, opcode.expr() - OpcodeId::EXTCODECOPY.expr()); + + cb.condition(is_extcodecopy.expr(), |cb| { + cb.call_context_lookup(false.expr(), None, CallContextFieldTag::TxId, tx_id.expr()); + + // Check if EXTCODECOPY external address is warm. + cb.account_access_list_read( + tx_id.expr(), + from_bytes::expr(&external_address.cells[..N_BYTES_ACCOUNT_ADDRESS]), + is_warm.expr(), + ); + + // EXTCODECOPY has an extra stack pop for external address. + cb.stack_pop(external_address.expr()); + }); + + cb.stack_pop(dst_offset.expr()); + cb.stack_pop(src_offset.expr()); + cb.stack_pop(copy_size.expr()); + + let dst_memory_addr = MemoryAddressGadget::construct(cb, dst_offset, copy_size); + let memory_expansion = MemoryExpansionGadget::construct(cb, [dst_memory_addr.address()]); + let memory_copier_gas = MemoryCopierGasGadget::construct( + cb, + dst_memory_addr.length(), + memory_expansion.gas_cost(), + ); + + let constant_gas_cost = select::expr( + is_extcodecopy.expr(), + // According to EIP-2929, EXTCODECOPY constant gas cost is different for cold and warm + // accounts. + select::expr( + is_warm.expr(), + GasCost::WARM_ACCESS.expr(), + GasCost::COLD_ACCOUNT_ACCESS.expr(), + ), + // Constant gas cost is same for CALLDATACOPY, CODECOPY and RETURNDATACOPY. + OpcodeId::CALLDATACOPY.constant_gas_cost().expr(), + ); + + let insufficient_gas = LtGadget::construct( + cb, + cb.curr.state.gas_left.expr(), + constant_gas_cost + memory_copier_gas.gas_cost(), + ); + + cb.require_equal( + "Gas left is less than gas cost", + insufficient_gas.expr(), + 1.expr(), + ); + + let common_error_gadget = CommonErrorGadget::construct( + cb, + opcode.expr(), + // EXTCODECOPY has extra 1 call context lookup (tx_id), 1 account access list + // read (is_warm), and 1 stack pop (external_address). + 5.expr() + 3.expr() * is_extcodecopy.expr(), + ); + + Self { + opcode, + is_warm, + tx_id, + external_address, + src_offset, + dst_memory_addr, + memory_expansion, + memory_copier_gas, + insufficient_gas, + is_extcodecopy, + common_error_gadget, + } + } + + fn assign_exec_step( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + block: &Block, + transaction: &Transaction, + call: &Call, + step: &ExecStep, + ) -> Result<(), Error> { + let opcode = step.opcode.unwrap(); + let is_extcodecopy = opcode == OpcodeId::EXTCODECOPY; + + log::debug!( + "ErrorOutOfGasMemoryCopy: opcode = {}, gas_left = {}, gas_cost = {}", + opcode, + step.gas_left, + step.gas_cost, + ); + + let (is_warm, external_address) = if is_extcodecopy { + ( + block.rws[step.rw_indices[1]].tx_access_list_value_pair().0, + block.rws[step.rw_indices[2]].stack_value(), + ) + } else { + (false, U256::zero()) + }; + + let rw_offset = if is_extcodecopy { 3 } else { 0 }; + let [dst_offset, src_offset, copy_size] = [rw_offset, rw_offset + 1, rw_offset + 2] + .map(|idx| block.rws[step.rw_indices[idx]].stack_value()); + + self.opcode + .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; + self.is_warm + .assign(region, offset, Value::known(F::from(u64::from(is_warm))))?; + self.tx_id + .assign(region, offset, Value::known(F::from(transaction.id as u64)))?; + self.external_address + .assign(region, offset, Some(external_address.to_le_bytes()))?; + self.src_offset + .assign(region, offset, Some(src_offset.to_le_bytes()))?; + let memory_addr = self + .dst_memory_addr + .assign(region, offset, dst_offset, copy_size)?; + let (_, memory_expansion_cost) = + self.memory_expansion + .assign(region, offset, step.memory_word_size(), [memory_addr])?; + let memory_copier_gas = self.memory_copier_gas.assign( + region, + offset, + copy_size.as_u64(), + memory_expansion_cost, + )?; + let constant_gas_cost = if is_extcodecopy { + if is_warm { + GasCost::WARM_ACCESS + } else { + GasCost::COLD_ACCOUNT_ACCESS + } + } else { + GasCost::FASTEST + }; + self.insufficient_gas.assign_value( + region, + offset, + Value::known(F::from(step.gas_left)), + Value::known(F::from(constant_gas_cost.0 + memory_copier_gas)), + )?; + self.is_extcodecopy.assign( + region, + offset, + F::from(opcode.as_u64()) - F::from(OpcodeId::EXTCODECOPY.as_u64()), + )?; + self.common_error_gadget.assign( + region, + offset, + block, + call, + step, + // EXTCODECOPY has extra 1 call context lookup (tx_id), 1 account access list + // read (is_warm), and 1 stack pop (external_address). + 5 + if is_extcodecopy { 3 } else { 0 }, + )?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + evm_circuit::test::{rand_bytes, rand_word}, + test_util::CircuitTestBuilder, + }; + use eth_types::{ + bytecode, evm_types::gas_utils::memory_copier_gas_cost, Bytecode, ToWord, U256, + }; + use itertools::Itertools; + use mock::{ + eth, test_ctx::helpers::account_0_code_account_1_no_code, TestContext, MOCK_ACCOUNTS, + }; + + const TESTING_COMMON_OPCODES: &[OpcodeId] = &[ + OpcodeId::CALLDATACOPY, + OpcodeId::CODECOPY, + OpcodeId::RETURNDATACOPY, + ]; + + const TESTING_DST_OFFSET_COPY_SIZE_PAIRS: &[(u64, u64)] = + &[(0x20, 0), (0x40, 20), (0x2000, 0x200)]; + + #[test] + fn test_oog_memory_copy_for_common_opcodes() { + for (opcode, (dst_offset, copy_size)) in TESTING_COMMON_OPCODES + .iter() + .cartesian_product(TESTING_DST_OFFSET_COPY_SIZE_PAIRS.iter()) + { + let testing_data = TestingData::new_for_common_opcode(*opcode, *dst_offset, *copy_size); + + test_root(&testing_data); + test_internal(&testing_data); + } + } + + #[test] + fn test_oog_memory_copy_for_extcodecopy() { + for (is_warm, (dst_offset, copy_size)) in [false, true] + .iter() + .cartesian_product(TESTING_DST_OFFSET_COPY_SIZE_PAIRS.iter()) + { + let testing_data = TestingData::new_for_extcodecopy(*is_warm, *dst_offset, *copy_size); + + test_root(&testing_data); + test_internal(&testing_data); + } + } + + struct TestingData { + bytecode: Bytecode, + gas_cost: u64, + } + + impl TestingData { + pub fn new_for_common_opcode(opcode: OpcodeId, dst_offset: u64, copy_size: u64) -> Self { + let bytecode = bytecode! { + PUSH32(copy_size) + PUSH32(rand_word()) + PUSH32(dst_offset) + .write_op(opcode) + }; + + let memory_word_size = (dst_offset + copy_size + 31) / 32; + + let gas_cost = OpcodeId::PUSH32.constant_gas_cost().0 * 3 + + opcode.constant_gas_cost().0 + + memory_copier_gas_cost(0, memory_word_size, copy_size); + + Self { bytecode, gas_cost } + } + + pub fn new_for_extcodecopy(is_warm: bool, dst_offset: u64, copy_size: u64) -> Self { + let external_address = MOCK_ACCOUNTS[4]; + + let mut bytecode = bytecode! { + PUSH32(copy_size) + PUSH32(U256::zero()) + PUSH32(dst_offset) + PUSH32(external_address.to_word()) + EXTCODECOPY + }; + + let memory_word_size = (dst_offset + copy_size + 31) / 32; + + let mut gas_cost = OpcodeId::PUSH32.constant_gas_cost().0 * 4 + + GasCost::COLD_ACCOUNT_ACCESS.0 + + memory_copier_gas_cost(0, memory_word_size, copy_size); + + if is_warm { + bytecode.append(&bytecode! { + PUSH32(copy_size) + PUSH32(rand_word()) + PUSH32(dst_offset) + PUSH32(external_address.to_word()) + EXTCODECOPY + }); + + gas_cost += OpcodeId::PUSH32.constant_gas_cost().0 * 4 + + GasCost::WARM_ACCESS.0 + + memory_copier_gas_cost(memory_word_size, memory_word_size, copy_size); + } + + Self { bytecode, gas_cost } + } + } + + fn test_root(testing_data: &TestingData) { + let ctx = TestContext::<2, 1>::new( + None, + account_0_code_account_1_no_code(testing_data.bytecode.clone()), + |mut txs, accs| { + // Decrease expected gas cost (by 1) to trigger out of gas error. + txs[0] + .from(accs[1].address) + .to(accs[0].address) + .gas((GasCost::TX.0 + testing_data.gas_cost - 1).into()); + }, + |block, _tx| block.number(0xcafe_u64), + ) + .unwrap(); + + CircuitTestBuilder::new_from_test_ctx(ctx).run(); + } + + fn test_internal(testing_data: &TestingData) { + let (addr_a, addr_b) = (MOCK_ACCOUNTS[0], MOCK_ACCOUNTS[1]); + + // code B gets called by code A, so the call is an internal call. + let code_b = testing_data.bytecode.clone(); + let gas_cost_b = testing_data.gas_cost; + + // Code A calls code B. + let code_a = bytecode! { + // populate memory in A's context. + PUSH8(U256::from_big_endian(&rand_bytes(8))) + PUSH1(0x00) // offset + MSTORE + // call ADDR_B. + PUSH1(0x00) // retLength + PUSH1(0x00) // retOffset + PUSH32(0x00) // argsLength + PUSH32(0x20) // argsOffset + PUSH1(0x00) // value + PUSH32(addr_b.to_word()) // addr + // Decrease expected gas cost (by 1) to trigger out of gas error. + PUSH32(gas_cost_b - 1) // gas + CALL + STOP + }; + + let ctx = TestContext::<3, 1>::new( + None, + |accs| { + accs[0].address(addr_b).code(code_b); + accs[1].address(addr_a).code(code_a); + accs[2].address(MOCK_ACCOUNTS[2]).balance(eth(10)); + }, + |mut txs, accs| { + txs[0].from(accs[2].address).to(accs[1].address); + }, + |block, _tx| block, + ) + .unwrap(); + + CircuitTestBuilder::new_from_test_ctx(ctx).run(); + } +} diff --git a/zkevm-circuits/src/witness/step.rs b/zkevm-circuits/src/witness/step.rs index bcc8e3bd37..b4ccc4f0e1 100644 --- a/zkevm-circuits/src/witness/step.rs +++ b/zkevm-circuits/src/witness/step.rs @@ -86,7 +86,6 @@ impl From<&ExecError> for ExecutionState { OogError::Log => ExecutionState::ErrorOutOfGasLOG, OogError::Exp => ExecutionState::ErrorOutOfGasEXP, OogError::Sha3 => ExecutionState::ErrorOutOfGasSHA3, - OogError::ExtCodeCopy => ExecutionState::ErrorOutOfGasEXTCODECOPY, OogError::Call => ExecutionState::ErrorOutOfGasCall, OogError::SloadSstore => ExecutionState::ErrorOutOfGasSloadSstore, OogError::Create2 => ExecutionState::ErrorOutOfGasCREATE2, From 4e64bdba9f5516bcde070c7087d06f149a0482bf Mon Sep 17 00:00:00 2001 From: Akase Cho Date: Fri, 21 Apr 2023 13:35:56 +0800 Subject: [PATCH 013/102] [refactor] refactor and add more helper in Bytecode (#1365) ### Description Refactor and add more helper functions to Bytecode: - Removed several functions such as `call`, `balance`, `mstore`, `calldatacopy`, and `return_bytecode` - Added `op_jumpdest` function - Implemented `impl_push_n` macro to generate functions for `op_push1` to `op_push32` - Implemented `impl_other_opcodes` macro to generate functions for various opcodes like `op_stop`, `op_add`, `op_mul`, `op_sub`, and so on - Renamed opcode helper functions to `op_{opcode}` for consistency and clarity ### Issue Link N/A ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - Removal of several functions - Addition of `op_jumpdest` function - Implementation of `impl_push_n` macro to generate functions for `op_push1` to `op_push32` - Implementation of `impl_other_opcodes` macro to generate functions for various opcodes - Renaming of opcode helper functions ### Rationale This refactor improves the code by removing unused functions, adding a new function, and implementing macros to generate functions for opcodes. The renaming of the opcode helper functions to `op_{opcode}` provides consistency and clarity to the codebase. ### How Has This Been Tested? https://github.com/scroll-tech/zkevm-circuits/actions/runs/4751119765 --- .../src/circuit_input_builder/tracer_tests.rs | 98 +++---- bus-mapping/src/evm/opcodes/balance.rs | 4 +- bus-mapping/src/evm/opcodes/calldatacopy.rs | 6 +- bus-mapping/src/evm/opcodes/logs.rs | 2 +- bus-mapping/src/evm/opcodes/sha3.rs | 4 +- eth-types/src/bytecode.rs | 267 +++++++++++++----- eth-types/src/evm_types/memory.rs | 2 +- mock/src/lib.rs | 4 +- .../src/evm_circuit/execution/balance.rs | 8 +- .../src/evm_circuit/execution/calldatacopy.rs | 2 +- .../src/evm_circuit/execution/dup.rs | 2 +- .../evm_circuit/execution/error_oog_call.rs | 2 +- .../execution/error_return_data_oo_bound.rs | 6 +- .../src/evm_circuit/execution/error_stack.rs | 2 +- .../src/evm_circuit/execution/logs.rs | 8 +- .../src/evm_circuit/execution/push.rs | 2 +- .../evm_circuit/execution/return_revert.rs | 4 +- .../evm_circuit/execution/returndatacopy.rs | 4 +- .../evm_circuit/execution/returndatasize.rs | 4 +- .../execution/signed_comparator.rs | 2 +- .../src/evm_circuit/execution/swap.rs | 2 +- zkevm-circuits/src/exp_circuit/test.rs | 6 +- zkevm-circuits/src/stats.rs | 2 +- 23 files changed, 268 insertions(+), 175 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index 39dc4fbeb0..6fe834a612 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -357,8 +357,8 @@ fn tracer_err_address_collision() { // that outputs the same, which will lead to the same new // contract address. let code_creator = bytecode! { - .mstore(0x00, 0x00) - .return_bytecode(0x00, 0x01) + .op_mstore(0x00, 0x00) + .op_return(0x00, 0x01) }; // code_a calls code_b which executes code_creator in CREATE2 @@ -385,9 +385,7 @@ fn tracer_err_address_collision() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH3(0x123456) // salt @@ -484,8 +482,8 @@ fn tracer_create_collision_free() { // that outputs not the same, which will lead to the different new // contract address. let code_creator = bytecode! { - .mstore(0x00, 0x00) - .return_bytecode(0x00, 0x01) + .op_mstore(0x00, 0x00) + .op_return(0x00, 0x01) }; // code_a calls code_b which executes code_creator in CREATE2 @@ -512,9 +510,7 @@ fn tracer_create_collision_free() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH1(len) // length @@ -624,8 +620,8 @@ fn tracer_err_code_store_out_of_gas() { // exhaust the gas to store the code. let code_len = 0x100; let code_creator = bytecode! { - .mstore(code_len, Word::zero()) - .return_bytecode(0x00, code_len) + .op_mstore(code_len, Word::zero()) + .op_return(0x00, code_len) }; // code_a calls code_b which executes code_creator in CREATE @@ -652,9 +648,7 @@ fn tracer_err_code_store_out_of_gas() { .chain(0..(32 - len % 32) as u8) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH32(len) // length @@ -717,8 +711,8 @@ fn tracer_err_code_store_out_of_gas_tx_deploy() { // exhaust the gas to store the code. let code_len = 0x100; let code_creator = bytecode! { - .mstore(code_len, Word::zero()) - .return_bytecode(0x00, code_len) + .op_mstore(code_len, Word::zero()) + .op_return(0x00, code_len) }; // Get the execution steps from the external tracer @@ -778,8 +772,8 @@ fn tracer_err_invalid_code() { // code_creator outputs byte array that starts with 0xef, which is // invalid code. let code_creator = bytecode! { - .mstore(0x00, word!("0xef00000000000000000000000000000000000000000000000000000000000000")) - .return_bytecode(0x00, 0x01) + .op_mstore(0x00, word!("0xef00000000000000000000000000000000000000000000000000000000000000")) + .op_return(0x00, 0x01) }; // code_a calls code_b which executes code_creator in CREATE @@ -806,9 +800,7 @@ fn tracer_err_invalid_code() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH1(len) // length @@ -880,8 +872,8 @@ fn tracer_err_max_code_size_exceeded() { // trigger the max code size limit. let code_len = 0x6000 + 1; let code_creator = bytecode! { - .mstore(code_len, Word::zero()) - .return_bytecode(0x00, code_len) + .op_mstore(code_len, Word::zero()) + .op_return(0x00, code_len) }; // code_a calls code_b which executes code_creator in CREATE @@ -908,9 +900,7 @@ fn tracer_err_max_code_size_exceeded() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH32(len) // length @@ -973,8 +963,8 @@ fn tracer_err_max_code_size_exceeded_tx_deploy() { // trigger the max code size limit. let code_len = 0x6000 + 1; let code_creator = bytecode! { - .mstore(code_len, Word::zero()) - .return_bytecode(0x00, code_len) + .op_mstore(code_len, Word::zero()) + .op_return(0x00, code_len) }; // Get the execution steps from the external tracer @@ -1022,7 +1012,7 @@ fn tracer_err_max_code_size_exceeded_tx_deploy() { fn tracer_create_stop() { // code_creator doesn't output anything because it stops. let code_creator = bytecode! { - .mstore(0x00, word!("0xef00000000000000000000000000000000000000000000000000000000000000")) + .op_mstore(0x00, word!("0xef00000000000000000000000000000000000000000000000000000000000000")) PUSH1(0x01) // length PUSH1(0x00) // offset STOP @@ -1052,9 +1042,7 @@ fn tracer_create_stop() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH1(len) // length @@ -1421,8 +1409,8 @@ fn tracer_err_return_data_out_of_bounds() { PUSH2(0xaa) }; let code_b = bytecode! { - .mstore(0x00, 0x42) - .return_bytecode(0x00, 0x01) + .op_mstore(0x00, 0x42) + .op_return(0x00, 0x01) }; // Get the execution steps from the external tracer let block: GethData = TestContext::<3, 2>::new_with_logger_config( @@ -1476,7 +1464,7 @@ fn tracer_err_gas_uint_overflow() { // MSTORE a value at an offset so high that the gast cost is big enough // to overflow an uint64 let code = bytecode! { - .mstore(0x100_0000_0000_0000_0000_u128, 0x42) + .op_mstore(0x100_0000_0000_0000_0000_u128, 0x42) }; let block: GethData = TestContext::<2, 1>::new_with_logger_config( None, @@ -1515,7 +1503,7 @@ fn tracer_err_gas_uint_overflow() { fn tracer_err_invalid_opcode() { // The second opcode is invalid (0x0f) let mut code = bytecode::Bytecode::default(); - code.write_op(OpcodeId::PC); + code.op_pc(); code.write(0x0f, true); let block: GethData = TestContext::<2, 1>::new_with_logger_config( None, @@ -1572,19 +1560,11 @@ fn tracer_err_write_protection(is_call: bool) { PUSH2(0xaa) }; - let mut code_b = bytecode! { - PUSH1(0x01) // value - PUSH1(0x02) // key - }; + let mut code_b = Bytecode::default(); if is_call { - code_b.push(1, Word::zero()); - code_b.push(1, Word::from(0x20)); - code_b.push(1, Word::from(0x10)); // value - code_b.push(32, *WORD_ADDR_B); // addr - code_b.push(32, Word::from(0x1000)); // gas - code_b.write_op(OpcodeId::CALL); + code_b.op_call(0x1000, *WORD_ADDR_B, 0x10, 0x20, 0, 0x02, 0x01); } else { - code_b.write_op(OpcodeId::SSTORE); + code_b.op_sstore(0x02, 0x01); } code_b.push(2, Word::from(0xbb)); @@ -1753,8 +1733,8 @@ fn tracer_err_stack_underflow() { fn create2_address() { // code_creator outputs 0x6050. let code_creator = bytecode! { - .mstore(0x00, word!("0x6050000000000000000000000000000000000000000000000000000000000000")) - .return_bytecode(0x00, 0x02) + .op_mstore(0x00, word!("0x6050000000000000000000000000000000000000000000000000000000000000")) + .op_return(0x00, 0x02) }; // code_a calls code_b which executes code_creator in CREATE @@ -1781,9 +1761,7 @@ fn create2_address() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH3(0x123456) // salt @@ -1851,8 +1829,8 @@ fn create2_address() { fn create_address() { // code_creator outputs 0x6050. let code_creator = bytecode! { - .mstore(0x00, word!("0x6050000000000000000000000000000000000000000000000000000000000000")) - .return_bytecode(0x00, 0x02) + .op_mstore(0x00, word!("0x6050000000000000000000000000000000000000000000000000000000000000")) + .op_return(0x00, 0x02) }; // code_a calls code_b which executes code_creator in CREATE @@ -1879,9 +1857,7 @@ fn create_address() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } // We do CREATE 2 times to use a nonce != 0 in the second one. let code_b_end = bytecode! { @@ -1977,7 +1953,7 @@ fn test_gen_access_trace() { PUSH2(0xaa) }; let code_b = bytecode! { - .mstore(0x01, word!("0x1234567890000000000000000000abcdef000000000000000000112233445566")) + .op_mstore(0x01, word!("0x1234567890000000000000000000abcdef000000000000000000112233445566")) PUSH1(0x01) // value PUSH1(0x02) // key SSTORE @@ -2202,9 +2178,7 @@ fn test_gen_access_trace_create_push_call_stack() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH1(len) // length diff --git a/bus-mapping/src/evm/opcodes/balance.rs b/bus-mapping/src/evm/opcodes/balance.rs index b30fd1acfc..1f58cf6712 100644 --- a/bus-mapping/src/evm/opcodes/balance.rs +++ b/bus-mapping/src/evm/opcodes/balance.rs @@ -125,12 +125,12 @@ mod balance_tests { let mut code = Bytecode::default(); if is_warm { code.append(&bytecode! { - .balance(address) + .op_balance(address) POP }); } code.append(&bytecode! { - .balance(address) + .op_balance(address) STOP }); diff --git a/bus-mapping/src/evm/opcodes/calldatacopy.rs b/bus-mapping/src/evm/opcodes/calldatacopy.rs index 2edd2879ba..04027f1c9a 100644 --- a/bus-mapping/src/evm/opcodes/calldatacopy.rs +++ b/bus-mapping/src/evm/opcodes/calldatacopy.rs @@ -202,7 +202,7 @@ mod calldatacopy_tests { let offset = 0x00usize; let copy_size = 0x10usize; let code_b = bytecode! { - .calldatacopy(dst_offset, offset, copy_size) + .op_calldatacopy(dst_offset, offset, copy_size) STOP }; @@ -378,7 +378,7 @@ mod calldatacopy_tests { // code B gets called by code A, so the call is an internal call. let code_b = bytecode! { - .calldatacopy(0x00usize, 0x00usize, 0x50usize) + .op_calldatacopy(0x00usize, 0x00usize, 0x50usize) STOP }; @@ -428,7 +428,7 @@ mod calldatacopy_tests { let calldata = vec![1, 3, 5, 7, 9, 2, 4, 6, 8]; let calldata_len = calldata.len(); let code = bytecode! { - .calldatacopy(dst_offset, offset, size) + .op_calldatacopy(dst_offset, offset, size) STOP }; diff --git a/bus-mapping/src/evm/opcodes/logs.rs b/bus-mapping/src/evm/opcodes/logs.rs index 3cf22faf95..aa68440c6d 100644 --- a/bus-mapping/src/evm/opcodes/logs.rs +++ b/bus-mapping/src/evm/opcodes/logs.rs @@ -252,7 +252,7 @@ mod log_tests { code.push(32, Word::from(msize)); code.push(32, Word::from(mstart)); code.write_op(cur_op_code); - code.write_op(OpcodeId::STOP); + code.op_stop(); // prepare memory data let pushdata = hex::decode("1234567890abcdef1234567890abcdef").unwrap(); diff --git a/bus-mapping/src/evm/opcodes/sha3.rs b/bus-mapping/src/evm/opcodes/sha3.rs index 75c2cf1a49..2179860d18 100644 --- a/bus-mapping/src/evm/opcodes/sha3.rs +++ b/bus-mapping/src/evm/opcodes/sha3.rs @@ -138,9 +138,7 @@ pub mod sha3_tests { mem_chunk.to_vec() }; memory.extend_from_slice(&mem_value); - code.push(32, Word::from_big_endian(&mem_value)); - code.push(32, 32 * i); - code.write_op(OpcodeId::MSTORE); + code.op_mstore(32 * i, Word::from_big_endian(&mem_value)); } // append SHA3 related opcodes at the tail end. let code_tail = bytecode! { diff --git a/eth-types/src/bytecode.rs b/eth-types/src/bytecode.rs index e62d71ec87..a72b30c682 100644 --- a/eth-types/src/bytecode.rs +++ b/eth-types/src/bytecode.rs @@ -149,76 +149,6 @@ impl Bytecode { self } - /// Call a contract - #[allow(clippy::too_many_arguments)] - pub fn call( - &mut self, - gas: T, - address: U, - value: V, - mem_in: W, - mem_in_size: X, - mem_out: Y, - mem_out_size: Z, - ) -> &mut Self { - self.append(&crate::bytecode! { - PUSH32(mem_out_size) - PUSH32(mem_out) - PUSH32(mem_in_size) - PUSH32(mem_in) - PUSH32(value) - PUSH32(address) - PUSH32(gas) - CALL - }); - self - } - - /// Balance - pub fn balance(&mut self, address: T) -> &mut Self { - self.append(&crate::bytecode! { - PUSH20(address) - BALANCE - }); - self - } - - /// mstore - pub fn mstore(&mut self, offset: T, value: U) -> &mut Self { - self.append(&crate::bytecode! { - PUSH32(value) - PUSH32(offset) - MSTORE - }); - self - } - - /// calldatacopy - pub fn calldatacopy( - &mut self, - dst_offset: T, - offset: U, - size: V, - ) -> &mut Self { - self.append(&crate::bytecode! { - PUSH32(size) - PUSH32(offset) - PUSH32(dst_offset) - CALLDATACOPY - }); - self - } - - /// return - pub fn return_bytecode(&mut self, offset: T, size: U) -> &mut Self { - self.append(&crate::bytecode! { - PUSH32(size) - PUSH32(offset) - RETURN - }); - self - } - /// Generate the diassembly pub fn disasm(&self) -> String { let mut asm = String::new(); @@ -255,6 +185,12 @@ impl Bytecode { pub fn iter(&self) -> BytecodeIterator<'_> { BytecodeIterator(self.code.iter()) } + + /// JUMPDEST opcode + pub fn op_jumpdest(&mut self) -> usize { + self.write_op(OpcodeId::JUMPDEST); + self.code.len() + } } /// An ASM entry @@ -402,6 +338,197 @@ macro_rules! bytecode_internal { }}; } +macro_rules! impl_push_n { + ($($push_n:ident, $n:expr)*) => { + #[allow(missing_docs)] + impl Bytecode { + $( + pub fn $push_n(&mut self, value: T) -> &mut Self { + self.push($n, value) + } + )* + } + }; +} + +impl_push_n! { + op_push1, 1 + op_push2, 2 + op_push3, 3 + op_push4, 4 + op_push5, 5 + op_push6, 6 + op_push7, 7 + op_push8, 8 + op_push9, 9 + op_push10, 10 + op_push11, 11 + op_push12, 12 + op_push13, 13 + op_push14, 14 + op_push15, 15 + op_push16, 16 + op_push17, 17 + op_push18, 18 + op_push19, 19 + op_push20, 20 + op_push21, 21 + op_push22, 22 + op_push23, 23 + op_push24, 24 + op_push25, 25 + op_push26, 26 + op_push27, 27 + op_push28, 28 + op_push29, 29 + op_push30, 30 + op_push31, 31 + op_push32, 32 +} + +macro_rules! impl_other_opcodes_inner { + ($self:ident, ) => {}; + ($self:ident, $arg:ident) => { + $self.op_push32($arg); + }; + ($self:ident, $arg:ident $($tail:ident)+) => { + impl_other_opcodes_inner!($self, $($tail)*); + $self.op_push32($arg); + } +} + +macro_rules! impl_other_opcodes { + ($(($op:ident, $x:ident $(, $arg:ident : $arg_ty:ident)*)),* $(,)?) => { + #[allow(missing_docs)] + #[allow(clippy::too_many_arguments)] + impl Bytecode { + $( + pub fn $op<$( + $arg_ty: ToWord, + )*>(&mut self, $($arg: $arg_ty),*) -> &mut Self { + impl_other_opcodes_inner!(self, $($arg)*); + self.write_op($crate::evm_types::OpcodeId::$x) + } + )* + } + }; +} + +impl_other_opcodes! { + (op_stop, STOP), + (op_add, ADD, a: A, b: B), + (op_mul, MUL, a: A, b: B), + (op_sub, SUB, a: A, b: B), + (op_div, DIV, a: A, b: B), + (op_sdiv, SDIV, a: A, b: B), + (op_mod, MOD, a: A, b: B), + (op_smod, SMOD, a: A, b: B), + (op_addmod, ADDMOD, a: A, b: B, n: N), + (op_mulmod, MULMOD, a: A, b: B, n: N), + (op_exp, EXP, a: A, exponent: B), + (op_signextend, SIGNEXTEND, b: A, x: B), + (op_lt, LT, a: A, b: B), + (op_gt, GT, a: A, b: B), + (op_slt, SLT, a: A, b: B), + (op_sgt, SGT, a: A, b: B), + (op_eq, EQ, a: A, b: B), + (op_iszero, ISZERO, a: A), + (op_and, AND, a: A, b: B), + (op_or, OR, a: A, b: B), + (op_xor, XOR, a: A, b: B), + (op_not, NOT, a: A), + (op_byte, BYTE, i: I, x: X), + (op_shl, SHL, shift: S, value: V), + (op_shr, SHR, shift: S, value: V), + (op_sar, SAR, shift: S, value: V), + (op_sha3, SHA3, offset: O, size: S), + (op_address, ADDRESS), + (op_balance, BALANCE, address: A), + (op_origin, ORIGIN), + (op_caller, CALLER), + (op_callvalue, CALLVALUE), + (op_calldataload, CALLDATALOAD, i: I), + (op_calldatasize, CALLDATASIZE), + (op_calldatacopy, CALLDATACOPY, dest_offset: D, offset: B, size: C), + (op_codesize, CODESIZE), + (op_codecopy, CODECOPY, dest_offset: D, offset: B, size: C), + (op_gasprice, GASPRICE), + (op_extcodesize, EXTCODESIZE, address: A), + (op_extcodecopy, EXTCODECOPY, address: A, dest_offset: D, offset: B, size: C), + (op_returndatasize, RETURNDATASIZE), + (op_returndatacopy, RETURNDATACOPY, dest_offset: D, offset: B, size: C), + (op_extcodehash, EXTCODEHASH, address: A), + (op_blockhash, BLOCKHASH, blocknumber: B), + (op_coinbase, COINBASE), + (op_timestamp, TIMESTAMP), + (op_number, NUMBER), + (op_prevrandao, DIFFICULTY), // alias for DIFFICULTY + (op_difficulty, DIFFICULTY), + (op_gaslimit, GASLIMIT), + (op_chainid, CHAINID), + (op_selfbalance, SELFBALANCE), + // (op_basefee, BASEFEE), ignored + (op_pop, POP), + (op_mload, MLOAD, offset: O), + (op_mstore, MSTORE, offset: O, value: V), + (op_mstore8, MSTORE8, offset: O, value: V), + (op_sload, SLOAD, offset: O), + (op_sstore, SSTORE, offset: O, value: V), + (op_jump, JUMP, counter: C), + (op_jumpi, JUMPI, counter: C), // branch not included + (op_pc, PC), + (op_msize, MSIZE), + (op_gas, GAS), + // (op_jumpdest, JUMPDEST), manually implemented + (op_dup1, DUP1), + (op_dup2, DUP2), + (op_dup3, DUP3), + (op_dup4, DUP4), + (op_dup5, DUP5), + (op_dup6, DUP6), + (op_dup7, DUP7), + (op_dup8, DUP8), + (op_dup9, DUP9), + (op_dup10, DUP10), + (op_dup11, DUP11), + (op_dup12, DUP12), + (op_dup13, DUP13), + (op_dup14, DUP14), + (op_dup15, DUP15), + (op_dup16, DUP16), + (op_swap1, SWAP1), + (op_swap2, SWAP2), + (op_swap3, SWAP3), + (op_swap4, SWAP4), + (op_swap5, SWAP5), + (op_swap6, SWAP6), + (op_swap7, SWAP7), + (op_swap8, SWAP8), + (op_swap9, SWAP9), + (op_swap10, SWAP10), + (op_swap11, SWAP11), + (op_swap12, SWAP12), + (op_swap13, SWAP13), + (op_swap14, SWAP14), + (op_swap15, SWAP15), + (op_swap16, SWAP16), + (op_log0, LOG0, offset: O, size: S), + (op_log1, LOG1, offset: O, size: S, topic1: T1), + (op_log2, LOG2, offset: O, size: S, topic1: T1, topic2: T2), + (op_log3, LOG3, offset: O, size: S, topic1: T1, topic2: T2, topic3: T3), + (op_log4, LOG4, offset: O, size: S, topic1: T1, topic2: T2, topic3: T3, topic4: T4), + (op_create, CREATE, value: V, offset: O, size: S), + (op_call, CALL, gas: G, address: A, value: V, args_offset: AO, args_size: AS, ret_offset: RO, ret_size: RS), + (op_callcode, CALLCODE, gas: G, address: A, value: V, args_offset: AO, args_size: AS, ret_offset: RO, ret_size: RS), + (op_return, RETURN, offset: O, size: S), + (op_delegatecall, DELEGATECALL, gas: G, address: A, args_offset: AO, args_size: AS, ret_offset: RO, ret_size: RS), + (op_create2, CREATE2, value: V, offset: O, size: SI, salt: SA), + (op_staticcall, STATICCALL, gas: G, address: A, args_offset: AO, args_size: AS, ret_offset: RO, ret_size: RS), + (op_revert, REVERT, offset: O, size: S), + // (op_invalid, INVALID), ignored + // (op_selfdestruct, SELFDESTRUCT), ignored +} + #[cfg(test)] mod tests { use super::*; diff --git a/eth-types/src/evm_types/memory.rs b/eth-types/src/evm_types/memory.rs index 7b0c599a8e..cb2d1f4fc9 100644 --- a/eth-types/src/evm_types/memory.rs +++ b/eth-types/src/evm_types/memory.rs @@ -336,7 +336,7 @@ impl Memory { self.extend_at_least(minimal_length); let mem_starts = dst_offset as usize; - let mem_ends = mem_starts + length as usize; + let mem_ends = mem_starts + length; let dst_slice = &mut self.0[mem_starts..mem_ends]; dst_slice.fill(0); let data_starts = data_offset as usize; diff --git a/mock/src/lib.rs b/mock/src/lib.rs index aad706f3e2..f190e0612c 100644 --- a/mock/src/lib.rs +++ b/mock/src/lib.rs @@ -129,11 +129,11 @@ impl Default for MockCallBytecodeParams { /// Generate mock EVM bytecode that performs a contract call pub fn generate_mock_call_bytecode(params: MockCallBytecodeParams) -> Bytecode { bytecode! { - .mstore( + .op_mstore( 0u64, Word::from_big_endian(¶ms.pushdata) ) - .call( + .op_call( params.gas, params.address, 0u64, diff --git a/zkevm-circuits/src/evm_circuit/execution/balance.rs b/zkevm-circuits/src/evm_circuit/execution/balance.rs index 04ed6277ca..eb4a6a0671 100644 --- a/zkevm-circuits/src/evm_circuit/execution/balance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/balance.rs @@ -202,12 +202,12 @@ mod test { let mut code = Bytecode::default(); if is_warm { code.append(&bytecode! { - .balance(address) + .op_balance(address) POP }); } code.append(&bytecode! { - .balance(address) + .op_balance(address) STOP }); @@ -253,12 +253,12 @@ mod test { let mut code_b = Bytecode::default(); if is_warm { code_b.append(&bytecode! { - .balance(address) + .op_balance(address) POP }); } code_b.append(&bytecode! { - .balance(address) + .op_balance(address) STOP }); diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index 69433e3910..6b8b1c9e8d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -307,7 +307,7 @@ mod test { // code B gets called by code A, so the call is an internal call. let code_b = bytecode! { - .calldatacopy(dst_offset, offset, length) + .op_calldatacopy(dst_offset, offset, length) STOP }; diff --git a/zkevm-circuits/src/evm_circuit/execution/dup.rs b/zkevm-circuits/src/evm_circuit/execution/dup.rs index f5fc855f07..cefb04b35c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/dup.rs +++ b/zkevm-circuits/src/evm_circuit/execution/dup.rs @@ -85,7 +85,7 @@ mod test { PUSH32(value) }; for _ in 0..n - 1 { - bytecode.write_op(OpcodeId::DUP1); + bytecode.op_dup1(); } bytecode.append(&bytecode! { .write_op(opcode) diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs index f0a423df67..4b133d7677 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs @@ -273,7 +273,7 @@ mod test { .write_op(opcode) PUSH1(0) PUSH1(0) - .write_op(OpcodeId::REVERT) + REVERT }); bytecode diff --git a/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs b/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs index 88c56218e7..6993a60709 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs @@ -204,7 +204,7 @@ mod test { if is_root { code_b.append(&bytecode! { - .return_bytecode(return_data_offset, return_data_size) + .op_return(return_data_offset, return_data_size) STOP }); } else { @@ -214,7 +214,7 @@ mod test { PUSH32(dest_offset) // memory offset RETURNDATACOPY // end for internal - .return_bytecode(return_data_offset, return_data_size) + .op_return(return_data_offset, return_data_size) STOP }); } @@ -242,7 +242,7 @@ mod test { }); } else { code_a.append(&bytecode! { - .return_bytecode(return_data_offset, return_data_size) + .op_return(return_data_offset, return_data_size) }); } diff --git a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs index a8550c6e68..63111c4a10 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs @@ -131,7 +131,7 @@ mod test { } } // append final stop op code - bytecode.write_op(OpcodeId::STOP); + bytecode.op_stop(); CircuitTestBuilder::new_from_test_ctx( TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(), diff --git a/zkevm-circuits/src/evm_circuit/execution/logs.rs b/zkevm-circuits/src/evm_circuit/execution/logs.rs index b82c3704e2..6e4889022a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/logs.rs +++ b/zkevm-circuits/src/evm_circuit/execution/logs.rs @@ -358,7 +358,7 @@ mod test { code.push(32, Word::from(mstart)); code.write_op(cur_op_code); if is_persistent { - code.write_op(OpcodeId::STOP); + code.op_stop(); } else { // make current call failed with false persistent code.write_op(OpcodeId::INVALID(0xfe)); @@ -415,7 +415,7 @@ mod test { code.push(32, Word::from(mstart)); code.write_op(cur_op_code); - code.write_op(OpcodeId::STOP); + code.op_stop(); code_prepare.append(&code); CircuitTestBuilder::new_from_test_ctx( @@ -430,9 +430,7 @@ mod test { // prepare memory data let mut code = Bytecode::default(); for (i, d) in data.chunks(32).enumerate() { - code.push(32, Word::from_big_endian(d)); - code.push(32, Word::from(offset + i * 32)); - code.write_op(OpcodeId::MSTORE); + code.op_mstore(offset + i * 32, Word::from_big_endian(d)); } code } diff --git a/zkevm-circuits/src/evm_circuit/execution/push.rs b/zkevm-circuits/src/evm_circuit/execution/push.rs index 7970c50eae..f2c28954bb 100644 --- a/zkevm-circuits/src/evm_circuit/execution/push.rs +++ b/zkevm-circuits/src/evm_circuit/execution/push.rs @@ -157,7 +157,7 @@ mod test { for b in bytes { bytecode.write(*b, false); } - bytecode.write_op(OpcodeId::STOP); + bytecode.op_stop(); CircuitTestBuilder::new_from_test_ctx( TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(), diff --git a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs index d417a3590f..cf5d0e8d2c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs +++ b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs @@ -602,9 +602,7 @@ mod test { .chain(0u8..((32 - initializer.len() % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - bytecode.push(32, Word::from_big_endian(word)); - bytecode.push(32, Word::from(index * 32)); - bytecode.write_op(OpcodeId::MSTORE); + bytecode.op_mstore(index * 32, Word::from_big_endian(word)); } bytecode.append(&bytecode! { PUSH3(0x123456) // salt diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs index 706be81dea..4b4392ff2a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs @@ -284,8 +284,8 @@ mod test { let return_offset = std::cmp::max((return_data_offset + return_data_size) as i64 - 32, 0) as usize; let code_b = bytecode! { - .mstore(return_offset, Word::from_big_endian(&rand_bytes(32))) - .return_bytecode(return_data_offset, return_data_size) + .op_mstore(return_offset, Word::from_big_endian(&rand_bytes(32))) + .op_return(return_data_offset, return_data_size) STOP }; diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs index 766e8628ac..82bae82f6e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs @@ -94,8 +94,8 @@ mod test { let (addr_a, addr_b) = (mock::MOCK_ACCOUNTS[0], mock::MOCK_ACCOUNTS[1]); let code_b = bytecode! { - .mstore(0, Word::from_big_endian(&rand_bytes(32))) - .return_bytecode(return_data_offset, return_data_size) + .op_mstore(0, Word::from_big_endian(&rand_bytes(32))) + .op_return(return_data_offset, return_data_size) STOP }; diff --git a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs index 069e3ad740..52eb0f9ec8 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs @@ -230,7 +230,7 @@ mod test { bytecode.push(32, a); bytecode.write_op(opcode); } - bytecode.write_op(OpcodeId::STOP); + bytecode.op_stop(); CircuitTestBuilder::new_from_test_ctx( TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(), diff --git a/zkevm-circuits/src/evm_circuit/execution/swap.rs b/zkevm-circuits/src/evm_circuit/execution/swap.rs index 55eb6f5556..5127fd2ad1 100644 --- a/zkevm-circuits/src/evm_circuit/execution/swap.rs +++ b/zkevm-circuits/src/evm_circuit/execution/swap.rs @@ -94,7 +94,7 @@ mod test { PUSH32(lhs) }; for _ in 0..n - 1 { - bytecode.write_op(OpcodeId::DUP1); + bytecode.op_dup1(); } bytecode.append(&bytecode! { PUSH32(rhs) diff --git a/zkevm-circuits/src/exp_circuit/test.rs b/zkevm-circuits/src/exp_circuit/test.rs index ecd032e1e5..ac168f7890 100644 --- a/zkevm-circuits/src/exp_circuit/test.rs +++ b/zkevm-circuits/src/exp_circuit/test.rs @@ -36,11 +36,9 @@ fn gen_code_single(base: Word, exponent: Word) -> Bytecode { fn gen_code_multiple(args: Vec<(Word, Word)>) -> Bytecode { let mut code = Bytecode::default(); for (base, exponent) in args.into_iter() { - code.push(32, exponent); - code.push(32, base); - code.write_op(OpcodeId::EXP); + code.op_exp(base, exponent); } - code.write_op(OpcodeId::STOP); + code.op_stop(); code } diff --git a/zkevm-circuits/src/stats.rs b/zkevm-circuits/src/stats.rs index 272bda9ed9..ed43527497 100644 --- a/zkevm-circuits/src/stats.rs +++ b/zkevm-circuits/src/stats.rs @@ -192,7 +192,7 @@ pub(crate) fn print_circuit_stats_by_states( code.write_op(opcode); let opcode_pc = code.code.len() - 1; // let opcode_step_index = (proxy_code.num_opcodes - 1 + code.num_opcodes) - 1; - code.write_op(OpcodeId::STOP); + code.op_stop(); let block: GethData = TestContext::<10, 1>::new( None, |accs| { From 757d1eee1ea3aad43431c5ec4e109eff04666f67 Mon Sep 17 00:00:00 2001 From: Akase Cho Date: Wed, 26 Apr 2023 12:23:34 +0800 Subject: [PATCH 014/102] [chore] upgrade toolchain to nightly-2023-04-24 (#1373) ### Description Upgrade toolchain to nightly-2023-04-24 for future compatibilities. ### Issue Link N/A ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - Toolchain upgrade to nightly-2023-04-24 - Fix lint errors ### Rationale The toolchain currently in use is outdated and lacks stable features. Issue #1372 requires GAT, which has been stabilized since version `1.65.0`. Meanwhile, the current stable Rust version is `1.69.0`. ### How Has This Been Tested? N/A --- bus-mapping/src/circuit_input_builder.rs | 4 ++-- bus-mapping/src/circuit_input_builder/access.rs | 2 +- .../src/circuit_input_builder/input_state_ref.rs | 10 +++++----- bus-mapping/src/error.rs | 4 ++-- bus-mapping/src/evm/opcodes/calldatacopy.rs | 2 +- bus-mapping/src/state_db.rs | 2 +- circuit-benchmarks/src/exp_circuit.rs | 2 +- circuit-benchmarks/src/pi_circuit.rs | 2 +- circuit-benchmarks/src/tx_circuit.rs | 2 +- eth-types/src/evm_types/memory.rs | 6 +++--- rust-toolchain | 2 +- testool/src/statetest/parse.rs | 2 +- testool/src/statetest/yaml.rs | 2 +- testool/src/utils.rs | 6 +++--- zkevm-circuits/src/bytecode_circuit/circuit.rs | 6 +++--- .../src/evm_circuit/execution/calldatacopy.rs | 2 +- .../src/evm_circuit/execution/extcodecopy.rs | 2 +- zkevm-circuits/src/evm_circuit/execution/msize.rs | 7 ++----- zkevm-circuits/src/evm_circuit/execution/sha3.rs | 8 ++------ zkevm-circuits/src/evm_circuit/step.rs | 2 +- zkevm-circuits/src/evm_circuit/util.rs | 4 ++-- zkevm-circuits/src/evm_circuit/util/common_gadget.rs | 7 ++----- .../src/evm_circuit/util/instrumentation.rs | 4 ++-- .../evm_circuit/util/math_gadget/batched_is_zero.rs | 2 +- zkevm-circuits/src/evm_circuit/util/memory_gadget.rs | 6 +++--- zkevm-circuits/src/keccak_circuit/cell_manager.rs | 12 ++---------- zkevm-circuits/src/pi_circuit.rs | 2 +- zkevm-circuits/src/test_util.rs | 4 +--- zkevm-circuits/src/witness/rw.rs | 4 ++-- 29 files changed, 50 insertions(+), 70 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 91696dead0..37c9a49e77 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -364,9 +364,9 @@ pub fn keccak_inputs_tx_circuit( } /// Retrieve the init_code from memory for {CREATE, CREATE2} -pub fn get_create_init_code<'a, 'b>( +pub fn get_create_init_code<'a>( call_ctx: &'a CallContext, - step: &'b GethExecStep, + step: &GethExecStep, ) -> Result<&'a [u8], Error> { let offset = step.stack.nth_last(1)?; let length = step.stack.nth_last(2)?; diff --git a/bus-mapping/src/circuit_input_builder/access.rs b/bus-mapping/src/circuit_input_builder/access.rs index 9d83cb7c45..d408138015 100644 --- a/bus-mapping/src/circuit_input_builder/access.rs +++ b/bus-mapping/src/circuit_input_builder/access.rs @@ -267,7 +267,7 @@ pub fn gen_state_access_trace( if call_stack.len() == 1 { return Err(Error::InvalidGethExecStep( "gen_state_access_trace: call stack will be empty", - step.clone(), + Box::new(step.clone()), )); } call_stack.pop().expect("call stack is empty"); diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index 9258676eab..22eda3249c 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -1225,7 +1225,7 @@ impl<'a> CircuitInputStateRef<'a> { _ => { return Err(Error::UnexpectedExecStepError( "call failure without return", - step.clone(), + Box::new(step.clone()), )); } }); @@ -1246,13 +1246,13 @@ impl<'a> CircuitInputStateRef<'a> { } else { return Err(Error::UnexpectedExecStepError( "failure in RETURN from {CREATE, CREATE2}", - step.clone(), + Box::new(step.clone()), )); } } else { return Err(Error::UnexpectedExecStepError( "failure in RETURN", - step.clone(), + Box::new(step.clone()), )); } } @@ -1272,7 +1272,7 @@ impl<'a> CircuitInputStateRef<'a> { { return Err(Error::UnexpectedExecStepError( "success result without {RETURN, STOP, SELFDESTRUCT}", - step.clone(), + Box::new(step.clone()), )); } @@ -1314,7 +1314,7 @@ impl<'a> CircuitInputStateRef<'a> { return Err(Error::UnexpectedExecStepError( "*CALL*/CREATE* code not executed", - step.clone(), + Box::new(step.clone()), )); } diff --git a/bus-mapping/src/error.rs b/bus-mapping/src/error.rs index 0c9914c1e3..cf3e4d8c46 100644 --- a/bus-mapping/src/error.rs +++ b/bus-mapping/src/error.rs @@ -28,12 +28,12 @@ pub enum Error { /// Code not found in the CodeDB CodeNotFound(H256), /// Unable to figure out error at a [`GethExecStep`] - UnexpectedExecStepError(&'static str, GethExecStep), + UnexpectedExecStepError(&'static str, Box), /// Invalid [`eth_types::GethExecTrace`] due to an invalid/unexpected value /// in it. InvalidGethExecTrace(&'static str), /// Invalid [`GethExecStep`] due to an invalid/unexpected value in it. - InvalidGethExecStep(&'static str, GethExecStep), + InvalidGethExecStep(&'static str, Box), /// Eth type related error. EthTypeError(eth_types::Error), /// EVM Execution error diff --git a/bus-mapping/src/evm/opcodes/calldatacopy.rs b/bus-mapping/src/evm/opcodes/calldatacopy.rs index 04027f1c9a..0500131d93 100644 --- a/bus-mapping/src/evm/opcodes/calldatacopy.rs +++ b/bus-mapping/src/evm/opcodes/calldatacopy.rs @@ -540,7 +540,7 @@ mod calldatacopy_tests { assert_eq!(copy_events[0].bytes.len(), size); for (idx, (value, is_code)) in copy_events[0].bytes.iter().enumerate() { - assert_eq!(value, calldata.get(offset as usize + idx).unwrap_or(&0)); + assert_eq!(value, calldata.get(offset + idx).unwrap_or(&0)); assert!(!is_code); } } diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index 33a563a424..227cb3bf9d 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -43,7 +43,7 @@ impl CodeDB { /// Compute hash of given code. pub fn hash(code: &[u8]) -> Hash { - H256(keccak256(&code)) + H256(keccak256(code)) } /// Code hash of empty code. diff --git a/circuit-benchmarks/src/exp_circuit.rs b/circuit-benchmarks/src/exp_circuit.rs index 28e1279178..35cb68f8a6 100644 --- a/circuit-benchmarks/src/exp_circuit.rs +++ b/circuit-benchmarks/src/exp_circuit.rs @@ -64,7 +64,7 @@ mod tests { // Bench setup generation let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); let start1 = start_timer!(|| setup_message); - let general_params = ParamsKZG::::setup(degree as u32, &mut rng); + let general_params = ParamsKZG::::setup(degree, &mut rng); let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); end_timer!(start1); diff --git a/circuit-benchmarks/src/pi_circuit.rs b/circuit-benchmarks/src/pi_circuit.rs index 1ca601296c..3f0b150882 100644 --- a/circuit-benchmarks/src/pi_circuit.rs +++ b/circuit-benchmarks/src/pi_circuit.rs @@ -68,7 +68,7 @@ mod tests { // Bench setup generation let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); let start1 = start_timer!(|| setup_message); - let general_params = ParamsKZG::::setup(degree as u32, &mut rng); + let general_params = ParamsKZG::::setup(degree, &mut rng); let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); end_timer!(start1); diff --git a/circuit-benchmarks/src/tx_circuit.rs b/circuit-benchmarks/src/tx_circuit.rs index 193803c937..4aa76da7ad 100644 --- a/circuit-benchmarks/src/tx_circuit.rs +++ b/circuit-benchmarks/src/tx_circuit.rs @@ -55,7 +55,7 @@ mod tests { // Bench setup generation let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); let start1 = start_timer!(|| setup_message); - let general_params = ParamsKZG::::setup(degree as u32, &mut rng); + let general_params = ParamsKZG::::setup(degree, &mut rng); let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); end_timer!(start1); diff --git a/eth-types/src/evm_types/memory.rs b/eth-types/src/evm_types/memory.rs index cb2d1f4fc9..e782475de2 100644 --- a/eth-types/src/evm_types/memory.rs +++ b/eth-types/src/evm_types/memory.rs @@ -373,10 +373,10 @@ mod memory_tests { let first_usize = 64536usize; // Parsing on both ways works. assert_eq!( - MemoryAddress::from_le_bytes(&first_usize.to_le_bytes())?, - MemoryAddress::from_be_bytes(&first_usize.to_be_bytes())? + MemoryAddress::from_le_bytes(first_usize.to_le_bytes())?, + MemoryAddress::from_be_bytes(first_usize.to_be_bytes())? ); - let addr = MemoryAddress::from_le_bytes(&first_usize.to_le_bytes())?; + let addr = MemoryAddress::from_le_bytes(first_usize.to_le_bytes())?; assert_eq!(addr, MemoryAddress::from(first_usize)); // Little endian export diff --git a/rust-toolchain b/rust-toolchain index 24b6d11f20..b6ce6a50ba 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2022-08-23 +nightly-2023-04-24 diff --git a/testool/src/statetest/parse.rs b/testool/src/statetest/parse.rs index 488e631b0d..2cd2d32a4e 100644 --- a/testool/src/statetest/parse.rs +++ b/testool/src/statetest/parse.rs @@ -41,7 +41,7 @@ fn decompose_tags(expr: &str) -> HashMap { } else { while !it.is_empty() { if it.starts_with(':') { - let tag = &it[..it.find(&[' ', '\n']).expect("unable to find end tag")]; + let tag = &it[..it.find([' ', '\n']).expect("unable to find end tag")]; it = &it[tag.len() + 1..]; let value_len = if tag == ":yul" || tag == ":solidity" || tag == ":asm" { it.len() diff --git a/testool/src/statetest/yaml.rs b/testool/src/statetest/yaml.rs index a6ae70ef68..20b8c4cd7c 100644 --- a/testool/src/statetest/yaml.rs +++ b/testool/src/statetest/yaml.rs @@ -264,7 +264,7 @@ impl<'a> YamlStateTestBuilder<'a> { } else { while !it.is_empty() { if it.starts_with(':') { - let tag = &it[..it.find(&[' ', '\n']).expect("unable to find end tag")]; + let tag = &it[..it.find([' ', '\n']).expect("unable to find end tag")]; it = &it[tag.len() + 1..]; let value_len = if tag == ":yul" || tag == ":solidity" { it.len() diff --git a/testool/src/utils.rs b/testool/src/utils.rs index c835987e50..6d8604d973 100644 --- a/testool/src/utils.rs +++ b/testool/src/utils.rs @@ -130,7 +130,7 @@ pub fn print_trace(trace: GethExecTrace) -> Result<()> { format!("{}", step.gas.0), format!("{}", step.gas_cost.0), format!("{}", step.depth), - step.error.unwrap_or_else(|| "".to_string()), + step.error.unwrap_or_default(), split(step.stack.0.iter().map(u256_to_str).collect(), 30), split(step.memory.0.iter().map(ToString::to_string).collect(), 30), split(kv(step.storage.0), 30) @@ -146,7 +146,7 @@ pub fn print_trace(trace: GethExecTrace) -> Result<()> { pub fn current_git_commit() -> Result { let output = Command::new("git") - .args(&["rev-parse", "HEAD"]) + .args(["rev-parse", "HEAD"]) .output() .unwrap(); let git_hash = String::from_utf8(output.stdout).unwrap(); @@ -156,7 +156,7 @@ pub fn current_git_commit() -> Result { pub fn current_submodule_git_commit() -> Result { let git_cmd = Command::new("git") - .args(&["ls-tree", "HEAD"]) + .args(["ls-tree", "HEAD"]) .stdout(Stdio::piped()) .output()?; diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 7f131fab06..3f5b6b0512 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -631,7 +631,7 @@ impl BytecodeCircuitConfig { push_data_left, value_rlc, length, - F::from(push_data_size as u64), + F::from(push_data_size), )?; trace!( @@ -865,8 +865,8 @@ impl BytecodeCircuit { pub fn new_from_block_sized(block: &witness::Block, bytecode_size: usize) -> Self { let bytecodes: Vec> = block .bytecodes - .iter() - .map(|(_, b)| unroll(b.bytes.clone())) + .values() + .map(|b| unroll(b.bytes.clone())) .collect(); Self::new(bytecodes, bytecode_size) } diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index 6b8b1c9e8d..352c7bcbd3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -240,7 +240,7 @@ impl ExecutionGadget for CallDataCopyGadget { region, offset, length.as_u64(), - memory_expansion_gas_cost as u64, + memory_expansion_gas_cost, )?; Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index 7949522b2b..55d887a57a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -226,7 +226,7 @@ impl ExecutionGadget for ExtcodecopyGadget { region, offset, memory_length.as_u64(), - memory_expansion_gas_cost as u64, + memory_expansion_gas_cost, )?; Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/execution/msize.rs b/zkevm-circuits/src/evm_circuit/execution/msize.rs index 3428f0a3e7..41d77eb2f5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/msize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/msize.rs @@ -67,11 +67,8 @@ impl ExecutionGadget for MsizeGadget { step: &ExecStep, ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - self.value.assign( - region, - offset, - Some((step.memory_size as u64).to_le_bytes()), - )?; + self.value + .assign(region, offset, Some((step.memory_size).to_le_bytes()))?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index f85fd1127e..761f37c3bf 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -146,12 +146,8 @@ impl ExecutionGadget for Sha3Gadget { step.memory_word_size(), [memory_address], )?; - self.memory_copier_gas.assign( - region, - offset, - size.as_u64(), - memory_expansion_gas_cost as u64, - )?; + self.memory_copier_gas + .assign(region, offset, size.as_u64(), memory_expansion_gas_cost)?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index 9658b871bb..8c83044bb3 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -576,7 +576,7 @@ impl Step { self.state.program_counter.assign( region, offset, - Value::known(F::from(step.program_counter as u64)), + Value::known(F::from(step.program_counter)), )?; self.state.stack_pointer.assign( region, diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 6749480939..eba13c13f1 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -289,7 +289,7 @@ impl CellType { } /// Return the storage phase of phase - pub(crate) fn storage_for_phase(phase: u8) -> CellType { + pub(crate) fn storage_for_phase(phase: u8) -> CellType { match phase { 0 => CellType::StoragePhase1, 1 => CellType::StoragePhase2, @@ -299,7 +299,7 @@ impl CellType { /// Return the storage cell of the expression pub(crate) fn storage_for_expr(expr: &Expression) -> CellType { - Self::storage_for_phase::(Self::expr_phase::(expr)) + Self::storage_for_phase(Self::expr_phase::(expr)) } } diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 2914907b9a..973987caed 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -79,11 +79,8 @@ impl SameContextGadget { self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; - self.sufficient_gas_left.assign( - region, - offset, - F::from((step.gas_left - step.gas_cost) as u64), - )?; + self.sufficient_gas_left + .assign(region, offset, F::from(step.gas_left - step.gas_cost))?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/util/instrumentation.rs b/zkevm-circuits/src/evm_circuit/util/instrumentation.rs index d38dd5ab72..103d34d202 100644 --- a/zkevm-circuits/src/evm_circuit/util/instrumentation.rs +++ b/zkevm-circuits/src/evm_circuit/util/instrumentation.rs @@ -20,10 +20,10 @@ pub(crate) struct Instrument { impl Instrument { /// Collects `CellManager` stats from a compiled EVMCircuit in order to /// extract metrics. - pub(crate) fn on_gadget_built<'a, F: FieldExt>( + pub(crate) fn on_gadget_built( &mut self, execution_state: ExecutionState, - cb: &ConstraintBuilder<'a, F>, + cb: &ConstraintBuilder<'_, F>, ) { let sizes = cb .curr diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs index 4d1817933b..8e3ca5965f 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs @@ -24,7 +24,7 @@ impl BatchedIsZeroGadget { .max() .expect("BatchedIsZeroGadget needs at least one expression"); - let cell_type = CellType::storage_for_phase::(max_values_phase); + let cell_type = CellType::storage_for_phase(max_values_phase); let is_zero = cb.query_bool_with_type(cell_type); let nonempty_witness = cb.query_cell_with_type(cell_type); diff --git a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs index f637a3c072..00d6846687 100644 --- a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs @@ -295,7 +295,7 @@ impl .collect::, _>>()?; // Calculate the next memory size - let mut next_memory_word_size = curr_memory_word_size as u64; + let mut next_memory_word_size = curr_memory_word_size; for (max_memory_word_sizes, memory_word_size) in self .max_memory_word_sizes .iter() @@ -304,7 +304,7 @@ impl let (_, max) = max_memory_word_sizes.assign( region, offset, - F::from(next_memory_word_size as u64), + F::from(next_memory_word_size), F::from(*memory_word_size), )?; next_memory_word_size = max.get_lower_128() as u64; @@ -324,7 +324,7 @@ impl // Calculate the gas cost for the expansian let memory_cost = GasCost::MEMORY_EXPANSION_LINEAR_COEFF.as_u64() - * (next_memory_word_size - curr_memory_word_size as u64) + * (next_memory_word_size - curr_memory_word_size) + (next_quad_memory_cost - curr_quad_memory_cost) as u64; // Return the new memory size and the memory expansion gas cost diff --git a/zkevm-circuits/src/keccak_circuit/cell_manager.rs b/zkevm-circuits/src/keccak_circuit/cell_manager.rs index 98fdaf4487..fe87a71ce3 100644 --- a/zkevm-circuits/src/keccak_circuit/cell_manager.rs +++ b/zkevm-circuits/src/keccak_circuit/cell_manager.rs @@ -59,11 +59,7 @@ impl Cell { } pub(crate) fn assign(&self, region: &mut KeccakRegion, offset: i32, value: F) { - region.assign( - self.column_idx, - ((offset as i32) + self.rotation) as usize, - value, - ); + region.assign(self.column_idx, (offset + self.rotation) as usize, value); } pub(crate) fn assign_value(&self, region: &mut KeccakRegion, offset: i32, value: Value) { @@ -73,11 +69,7 @@ impl Cell { // this shouldn't be needed. let value_f = extract_field(value); - region.assign( - self.column_idx, - ((offset as i32) + self.rotation) as usize, - value_f, - ); + region.assign(self.column_idx, (offset + self.rotation) as usize, value_f); } } diff --git a/zkevm-circuits/src/pi_circuit.rs b/zkevm-circuits/src/pi_circuit.rs index 44ba6e375e..0a7875837e 100644 --- a/zkevm-circuits/src/pi_circuit.rs +++ b/zkevm-circuits/src/pi_circuit.rs @@ -1391,7 +1391,7 @@ impl SubCircuit for PiCircuit { &mut region, offset, i + 1, - tx_id_next as usize, + tx_id_next, index, F::from(*byte as u64), is_final, diff --git a/zkevm-circuits/src/test_util.rs b/zkevm-circuits/src/test_util.rs index 4e3d17e337..0697c777ae 100644 --- a/zkevm-circuits/src/test_util.rs +++ b/zkevm-circuits/src/test_util.rs @@ -229,9 +229,7 @@ impl CircuitTestBuilder { .iter() .filter(|rw| !matches!(rw, Rw::Start { .. })) .count(); - let rows = (params.max_rws - non_start_rows_len..params.max_rws) - .into_iter() - .collect(); + let rows = (params.max_rws - non_start_rows_len..params.max_rws).collect(); self.state_checks.as_ref()(prover, &rows, &rows); } diff --git a/zkevm-circuits/src/witness/rw.rs b/zkevm-circuits/src/witness/rw.rs index 18f98e0704..27999b8b27 100644 --- a/zkevm-circuits/src/witness/rw.rs +++ b/zkevm-circuits/src/witness/rw.rs @@ -392,7 +392,7 @@ impl Rw { tag: F::from(self.tag() as u64), id: F::from(self.id().unwrap_or_default() as u64), address: self.address().unwrap_or_default().to_scalar().unwrap(), - field_tag: F::from(self.field_tag().unwrap_or_default() as u64), + field_tag: F::from(self.field_tag().unwrap_or_default()), storage_key: rlc::value( &self.storage_key().unwrap_or_default().to_le_bytes(), randomness, @@ -413,7 +413,7 @@ impl Rw { tag: Value::known(F::from(self.tag() as u64)), id: Value::known(F::from(self.id().unwrap_or_default() as u64)), address: Value::known(self.address().unwrap_or_default().to_scalar().unwrap()), - field_tag: Value::known(F::from(self.field_tag().unwrap_or_default() as u64)), + field_tag: Value::known(F::from(self.field_tag().unwrap_or_default())), storage_key: randomness.map(|randomness| { rlc::value( &self.storage_key().unwrap_or_default().to_le_bytes(), From 3902437a553d71c826782ebe0930693abcd60d2c Mon Sep 17 00:00:00 2001 From: Leo Lara Date: Wed, 26 Apr 2023 13:48:15 +0700 Subject: [PATCH 015/102] Deduplicate code between evm ConstraintBuilder and BaseConstraintBuilder (#1318) ### Description evm ConstraintBuilder and BaseConstraintBuilder have: require_zero require_equal require_boolean require_in_set condition add_constraints add_constraint validate_degree all with very similar implementation. Deduplicate them ### Issue Link https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1202 ### Type of change - Refactor ### Contents - Created a trait for common code. ### Rationale DRY ### How Has This Been Tested? Run tests. ### Notes (TODO?) - condition and validate_degree use the state, I don't know what could be the rusty way of making this code common. - Perhaps we should rethought the names of the trait and structs, BaseConstraintBuilder seems to be used mostly outside EVM circuit, while ConstraintBuilder is used in the EVM circuit exclusively. --------- Co-authored-by: adria0.eth <5526331+adria0@users.noreply.github.com> --- .../src/bytecode_circuit/circuit.rs | 6 +- zkevm-circuits/src/copy_circuit.rs | 2 +- zkevm-circuits/src/evm_circuit/execution.rs | 12 +- .../src/evm_circuit/execution/add_sub.rs | 4 +- .../src/evm_circuit/execution/addmod.rs | 7 +- .../src/evm_circuit/execution/address.rs | 4 +- .../src/evm_circuit/execution/balance.rs | 5 +- .../src/evm_circuit/execution/begin_tx.rs | 4 +- .../src/evm_circuit/execution/bitwise.rs | 4 +- .../src/evm_circuit/execution/block_ctx.rs | 10 +- .../src/evm_circuit/execution/blockhash.rs | 7 +- .../src/evm_circuit/execution/byte.rs | 4 +- .../src/evm_circuit/execution/calldatacopy.rs | 4 +- .../src/evm_circuit/execution/calldataload.rs | 7 +- .../src/evm_circuit/execution/calldatasize.rs | 4 +- .../src/evm_circuit/execution/caller.rs | 4 +- .../src/evm_circuit/execution/callop.rs | 4 +- .../src/evm_circuit/execution/callvalue.rs | 4 +- .../src/evm_circuit/execution/chainid.rs | 4 +- .../src/evm_circuit/execution/codecopy.rs | 6 +- .../src/evm_circuit/execution/codesize.rs | 6 +- .../src/evm_circuit/execution/comparator.rs | 4 +- .../src/evm_circuit/execution/dummy.rs | 4 +- .../src/evm_circuit/execution/dup.rs | 4 +- .../src/evm_circuit/execution/end_block.rs | 6 +- .../src/evm_circuit/execution/end_tx.rs | 4 +- .../execution/error_invalid_jump.rs | 4 +- .../execution/error_invalid_opcode.rs | 5 +- .../evm_circuit/execution/error_oog_call.rs | 4 +- .../execution/error_oog_constant.rs | 8 +- .../evm_circuit/execution/error_oog_exp.rs | 4 +- .../evm_circuit/execution/error_oog_log.rs | 4 +- .../execution/error_oog_memory_copy.rs | 4 +- .../execution/error_oog_sload_sstore.rs | 4 +- .../execution/error_oog_static_memory.rs | 4 +- .../execution/error_return_data_oo_bound.rs | 4 +- .../src/evm_circuit/execution/error_stack.rs | 6 +- .../execution/error_write_protection.rs | 8 +- .../src/evm_circuit/execution/exp.rs | 6 +- .../src/evm_circuit/execution/extcodecopy.rs | 5 +- .../src/evm_circuit/execution/extcodehash.rs | 4 +- .../src/evm_circuit/execution/extcodesize.rs | 5 +- .../src/evm_circuit/execution/gas.rs | 7 +- .../src/evm_circuit/execution/gasprice.rs | 4 +- .../src/evm_circuit/execution/is_zero.rs | 4 +- .../src/evm_circuit/execution/jump.rs | 4 +- .../src/evm_circuit/execution/jumpdest.rs | 4 +- .../src/evm_circuit/execution/jumpi.rs | 4 +- .../src/evm_circuit/execution/logs.rs | 4 +- .../src/evm_circuit/execution/memory.rs | 4 +- .../src/evm_circuit/execution/msize.rs | 7 +- .../src/evm_circuit/execution/mul_div_mod.rs | 7 +- .../src/evm_circuit/execution/mulmod.rs | 7 +- .../src/evm_circuit/execution/not.rs | 4 +- .../src/evm_circuit/execution/origin.rs | 4 +- .../src/evm_circuit/execution/pc.rs | 7 +- .../src/evm_circuit/execution/pop.rs | 4 +- .../src/evm_circuit/execution/push.rs | 7 +- .../evm_circuit/execution/return_revert.rs | 4 +- .../evm_circuit/execution/returndatacopy.rs | 4 +- .../evm_circuit/execution/returndatasize.rs | 4 +- .../src/evm_circuit/execution/sar.rs | 7 +- .../src/evm_circuit/execution/sdiv_smod.rs | 7 +- .../src/evm_circuit/execution/selfbalance.rs | 4 +- .../src/evm_circuit/execution/sha3.rs | 6 +- .../src/evm_circuit/execution/shl_shr.rs | 7 +- .../execution/signed_comparator.rs | 4 +- .../src/evm_circuit/execution/signextend.rs | 7 +- .../src/evm_circuit/execution/sload.rs | 4 +- .../src/evm_circuit/execution/sstore.rs | 7 +- .../src/evm_circuit/execution/stop.rs | 4 +- .../src/evm_circuit/execution/swap.rs | 4 +- .../src/evm_circuit/util/common_gadget.rs | 21 +-- .../evm_circuit/util/constraint_builder.rs | 147 +++++++----------- .../src/evm_circuit/util/instrumentation.rs | 4 +- .../evm_circuit/util/math_gadget/abs_word.rs | 11 +- .../evm_circuit/util/math_gadget/add_words.rs | 9 +- .../util/math_gadget/batched_is_zero.rs | 7 +- .../util/math_gadget/binary_number.rs | 7 +- .../evm_circuit/util/math_gadget/byte_size.rs | 9 +- .../evm_circuit/util/math_gadget/cmp_words.rs | 7 +- .../util/math_gadget/comparison.rs | 8 +- .../util/math_gadget/constant_division.rs | 9 +- .../evm_circuit/util/math_gadget/is_equal.rs | 10 +- .../evm_circuit/util/math_gadget/is_zero.rs | 14 +- .../src/evm_circuit/util/math_gadget/lt.rs | 8 +- .../evm_circuit/util/math_gadget/lt_word.rs | 8 +- .../evm_circuit/util/math_gadget/min_max.rs | 9 +- .../evm_circuit/util/math_gadget/modulo.rs | 9 +- .../util/math_gadget/mul_add_words.rs | 9 +- .../util/math_gadget/mul_add_words512.rs | 9 +- .../util/math_gadget/mul_word_u64.rs | 9 +- .../util/math_gadget/pair_select.rs | 11 +- .../util/math_gadget/range_check.rs | 7 +- .../src/evm_circuit/util/math_gadget/rlp.rs | 28 ++-- .../evm_circuit/util/math_gadget/test_util.rs | 6 +- .../src/evm_circuit/util/memory_gadget.rs | 17 +- zkevm-circuits/src/exp_circuit.rs | 2 + zkevm-circuits/src/keccak_circuit.rs | 15 +- .../src/keccak_circuit/cell_manager.rs | 4 +- .../src/keccak_circuit/keccak_packed_multi.rs | 4 +- zkevm-circuits/src/util/cell_manager.rs | 8 + 102 files changed, 447 insertions(+), 347 deletions(-) create mode 100644 zkevm-circuits/src/util/cell_manager.rs diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 3f5b6b0512..b0235abaaa 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -1,5 +1,9 @@ use crate::{ - evm_circuit::util::{and, constraint_builder::BaseConstraintBuilder, not, or, rlc, select}, + evm_circuit::util::{ + and, + constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, + not, or, rlc, select, + }, table::{BytecodeFieldTag, BytecodeTable, KeccakTable, LookupTable}, util::{get_push_size, Challenges, Expr, SubCircuit, SubCircuitConfig}, witness, diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index 57a83fded2..c0fa935714 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -27,7 +27,7 @@ use itertools::Itertools; use std::{collections::HashMap, marker::PhantomData}; use crate::{ - evm_circuit::util::constraint_builder::BaseConstraintBuilder, + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, table::{ BytecodeFieldTag, BytecodeTable, CopyTable, LookupTable, RwTable, RwTableTag, TxContextFieldTag, TxTable, diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index ff44ee7e5a..c7bea3d2cd 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -12,7 +12,9 @@ use crate::{ step::{ExecutionState, Step}, table::Table, util::{ - constraint_builder::{BaseConstraintBuilder, ConstraintBuilder}, + constraint_builder::{ + BaseConstraintBuilder, ConstrainBuilderCommon, EVMConstraintBuilder, + }, rlc, CellType, }, witness::{Block, Call, ExecStep, Transaction}, @@ -182,7 +184,7 @@ pub(crate) trait ExecutionGadget { const EXECUTION_STATE: ExecutionState; - fn configure(cb: &mut ConstraintBuilder) -> Self; + fn configure(cb: &mut EVMConstraintBuilder) -> Self; fn assign_exec_step( &self, @@ -617,7 +619,7 @@ impl ExecutionConfig { // height let height = { let dummy_step_next = Step::new(meta, advices, MAX_STEP_HEIGHT, true); - let mut cb = ConstraintBuilder::new( + let mut cb = EVMConstraintBuilder::new( step_curr.clone(), dummy_step_next, challenges, @@ -630,7 +632,7 @@ impl ExecutionConfig { // Now actually configure the gadget with the correct minimal height let step_next = &Step::new(meta, advices, height, true); - let mut cb = ConstraintBuilder::new( + let mut cb = EVMConstraintBuilder::new( step_curr.clone(), step_next.clone(), challenges, @@ -676,7 +678,7 @@ impl ExecutionConfig { name: &'static str, execution_state: ExecutionState, height: usize, - mut cb: ConstraintBuilder, + mut cb: EVMConstraintBuilder, ) { // Enforce the step height for this opcode let num_rows_until_next_step_next = query_expression(meta, |meta| { diff --git a/zkevm-circuits/src/evm_circuit/execution/add_sub.rs b/zkevm-circuits/src/evm_circuit/execution/add_sub.rs index d604d636b0..fb6e457e27 100644 --- a/zkevm-circuits/src/evm_circuit/execution/add_sub.rs +++ b/zkevm-circuits/src/evm_circuit/execution/add_sub.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget::{AddWordsGadget, PairSelectGadget}, select, CachedRegion, }, @@ -32,7 +32,7 @@ impl ExecutionGadget for AddSubGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ADD_SUB; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let a = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/addmod.rs b/zkevm-circuits/src/evm_circuit/execution/addmod.rs index 45bc6c6200..51d350c096 100644 --- a/zkevm-circuits/src/evm_circuit/execution/addmod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/addmod.rs @@ -4,7 +4,10 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, math_gadget::{ AddWordsGadget, CmpWordsGadget, IsZeroGadget, MulAddWords512Gadget, MulAddWordsGadget, @@ -49,7 +52,7 @@ impl ExecutionGadget for AddModGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ADDMOD; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); // values got from stack (original r is modified if n==0) diff --git a/zkevm-circuits/src/evm_circuit/execution/address.rs b/zkevm-circuits/src/evm_circuit/execution/address.rs index bca707c3b8..508cabcd61 100644 --- a/zkevm-circuits/src/evm_circuit/execution/address.rs +++ b/zkevm-circuits/src/evm_circuit/execution/address.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, @@ -29,7 +29,7 @@ impl ExecutionGadget for AddressGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ADDRESS; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let address = cb.query_word_rlc(); // Lookup callee address in call context. diff --git a/zkevm-circuits/src/evm_circuit/execution/balance.rs b/zkevm-circuits/src/evm_circuit/execution/balance.rs index eb4a6a0671..9a923308ff 100644 --- a/zkevm-circuits/src/evm_circuit/execution/balance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/balance.rs @@ -6,7 +6,8 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ - ConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, + ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, + Transition::Delta, }, from_bytes, math_gadget::IsZeroGadget, @@ -37,7 +38,7 @@ impl ExecutionGadget for BalanceGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BALANCE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let address_word = cb.query_word_rlc(); let address = from_bytes::expr(&address_word.cells[..N_BYTES_ACCOUNT_ADDRESS]); cb.stack_pop(address_word.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index d9e2dee456..1958b308b7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -7,7 +7,7 @@ use crate::{ and, common_gadget::TransferWithGasFeeGadget, constraint_builder::{ - ConstraintBuilder, ReversionInfo, StepStateTransition, + ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::{Delta, To}, }, is_precompiled, @@ -58,7 +58,7 @@ impl ExecutionGadget for BeginTxGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BeginTx; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { // Use rw_counter of the step which triggers next call as its call_id. let call_id = cb.curr.state.rw_counter.clone(); diff --git a/zkevm-circuits/src/evm_circuit/execution/bitwise.rs b/zkevm-circuits/src/evm_circuit/execution/bitwise.rs index e6f5a3e7f6..90979590fa 100644 --- a/zkevm-circuits/src/evm_circuit/execution/bitwise.rs +++ b/zkevm-circuits/src/evm_circuit/execution/bitwise.rs @@ -5,7 +5,7 @@ use crate::{ table::{FixedTableTag, Lookup}, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, CachedRegion, Word, }, witness::{Block, Call, ExecStep, Transaction}, @@ -28,7 +28,7 @@ impl ExecutionGadget for BitwiseGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BITWISE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let a = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs index b594928b12..31ed3e8a16 100644 --- a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, @@ -24,7 +24,7 @@ pub(crate) struct BlockCtxGadget { } impl BlockCtxGadget { - fn construct(cb: &mut ConstraintBuilder) -> Self { + fn construct(cb: &mut EVMConstraintBuilder) -> Self { let value = cb.query_word_rlc(); // Push the const generic parameter N_BYTES value to the stack @@ -71,7 +71,7 @@ impl ExecutionGadget for BlockCtxU64Gadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BLOCKCTXU64; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let value_u64 = BlockCtxGadget::construct(cb); Self { value_u64 } @@ -112,7 +112,7 @@ impl ExecutionGadget for BlockCtxU160Gadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BLOCKCTXU160; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let value_u160 = BlockCtxGadget::construct(cb); Self { value_u160 } @@ -157,7 +157,7 @@ impl ExecutionGadget for BlockCtxU256Gadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BLOCKCTXU256; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let value_u256 = BlockCtxGadget::construct(cb); Self { value_u256 } diff --git a/zkevm-circuits/src/evm_circuit/execution/blockhash.rs b/zkevm-circuits/src/evm_circuit/execution/blockhash.rs index 4ddcf450a6..97af6df77b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/blockhash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/blockhash.rs @@ -5,7 +5,10 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, from_bytes, math_gadget::LtGadget, CachedRegion, Cell, RandomLinearCombination, Word, @@ -35,7 +38,7 @@ impl ExecutionGadget for BlockHashGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BLOCKHASH; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let block_number = cb.query_word_rlc(); cb.stack_pop(block_number.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/byte.rs b/zkevm-circuits/src/evm_circuit/execution/byte.rs index 2d44757959..dd4b4317d7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/byte.rs +++ b/zkevm-circuits/src/evm_circuit/execution/byte.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget::{IsEqualGadget, IsZeroGadget}, sum, CachedRegion, Word, }, @@ -31,7 +31,7 @@ impl ExecutionGadget for ByteGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BYTE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let index = cb.query_word_rlc(); let value = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index 352c7bcbd3..6296bb2874 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ - ConstraintBuilder, StepStateTransition, + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, from_bytes, @@ -42,7 +42,7 @@ impl ExecutionGadget for CallDataCopyGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CALLDATACOPY; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let memory_offset = cb.query_cell_phase2(); diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs index fcfe7cf704..6931647404 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs @@ -11,7 +11,10 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, from_bytes, memory_gadget::BufferReaderGadget, not, CachedRegion, Cell, MemoryAddress, @@ -53,7 +56,7 @@ impl ExecutionGadget for CallDataLoadGadget { const NAME: &'static str = "CALLDATALOAD"; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let offset = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs index c9d36227a5..e9485a61eb 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, @@ -28,7 +28,7 @@ impl ExecutionGadget for CallDataSizeGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CALLDATASIZE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); // Add lookup constraint in the call context for the calldatasize field. diff --git a/zkevm-circuits/src/evm_circuit/execution/caller.rs b/zkevm-circuits/src/evm_circuit/execution/caller.rs index 6ea37242db..19bc8f79ae 100644 --- a/zkevm-circuits/src/evm_circuit/execution/caller.rs +++ b/zkevm-circuits/src/evm_circuit/execution/caller.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, @@ -29,7 +29,7 @@ impl ExecutionGadget for CallerGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CALLER; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let caller_address = cb.query_word_rlc(); // Lookup rw_table -> call_context with caller address diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index d8058324e2..ac3fae4f3b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -5,7 +5,7 @@ use crate::evm_circuit::{ util::{ common_gadget::{CommonCallGadget, TransferGadget}, constraint_builder::{ - ConstraintBuilder, ReversionInfo, StepStateTransition, + ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::{Delta, To}, }, math_gadget::{ConstantDivisionGadget, IsZeroGadget, LtWordGadget, MinMaxGadget}, @@ -58,7 +58,7 @@ impl ExecutionGadget for CallOpGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CALL_OP; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); cb.opcode_lookup(opcode.expr(), 1.expr()); let is_call = IsZeroGadget::construct(cb, opcode.expr() - OpcodeId::CALL.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs index cbb8d9345d..12a9e95f2c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, @@ -29,7 +29,7 @@ impl ExecutionGadget for CallValueGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CALLVALUE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let call_value = cb.query_cell_phase2(); // Lookup rw_table -> call_context with call value diff --git a/zkevm-circuits/src/evm_circuit/execution/chainid.rs b/zkevm-circuits/src/evm_circuit/execution/chainid.rs index d331aa78ec..6f6146e626 100644 --- a/zkevm-circuits/src/evm_circuit/execution/chainid.rs +++ b/zkevm-circuits/src/evm_circuit/execution/chainid.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, @@ -27,7 +27,7 @@ impl ExecutionGadget for ChainIdGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CHAINID; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let chain_id = cb.query_cell_phase2(); // Push the value to the stack diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index 878d9f05b8..17a8258d47 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -8,7 +8,9 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition, + }, from_bytes, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, not, CachedRegion, Cell, MemoryAddress, @@ -46,7 +48,7 @@ impl ExecutionGadget for CodeCopyGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CODECOPY; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); // Query elements to be popped from the stack. diff --git a/zkevm-circuits/src/evm_circuit/execution/codesize.rs b/zkevm-circuits/src/evm_circuit/execution/codesize.rs index 33d8ffe818..bd98f3ea76 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codesize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codesize.rs @@ -8,7 +8,9 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition, + }, from_bytes, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, @@ -30,7 +32,7 @@ impl ExecutionGadget for CodesizeGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CODESIZE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let codesize_bytes = array_init(|_| cb.query_byte()); diff --git a/zkevm-circuits/src/evm_circuit/execution/comparator.rs b/zkevm-circuits/src/evm_circuit/execution/comparator.rs index 3e1dccd893..c11803c352 100644 --- a/zkevm-circuits/src/evm_circuit/execution/comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/comparator.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, math_gadget::{ComparisonGadget, IsEqualGadget}, select, CachedRegion, Cell, Word, @@ -33,7 +33,7 @@ impl ExecutionGadget for ComparatorGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::CMP; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let a = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/dummy.rs b/zkevm-circuits/src/evm_circuit/execution/dummy.rs index 906c0009a9..693b533baf 100644 --- a/zkevm-circuits/src/evm_circuit/execution/dummy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/dummy.rs @@ -4,7 +4,7 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, step::ExecutionState, - util::{constraint_builder::ConstraintBuilder, CachedRegion, Word}, + util::{constraint_builder::EVMConstraintBuilder, CachedRegion, Word}, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, @@ -26,7 +26,7 @@ impl const EXECUTION_STATE: ExecutionState = S; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let pops: [Word; N_POP] = [(); N_POP].map(|_| cb.query_word_rlc()); let pushes: [Word; N_PUSH] = [(); N_PUSH].map(|_| cb.query_word_rlc()); for pop in pops.iter() { diff --git a/zkevm-circuits/src/evm_circuit/execution/dup.rs b/zkevm-circuits/src/evm_circuit/execution/dup.rs index cefb04b35c..51c808b978 100644 --- a/zkevm-circuits/src/evm_circuit/execution/dup.rs +++ b/zkevm-circuits/src/evm_circuit/execution/dup.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, @@ -25,7 +25,7 @@ impl ExecutionGadget for DupGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::DUP; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let value = cb.query_cell_phase2(); diff --git a/zkevm-circuits/src/evm_circuit/execution/end_block.rs b/zkevm-circuits/src/evm_circuit/execution/end_block.rs index 2a39bdbbf0..ed07de8da2 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_block.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_block.rs @@ -3,7 +3,9 @@ use crate::{ execution::ExecutionGadget, step::ExecutionState, util::{ - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Same}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::Same, + }, math_gadget::{IsEqualGadget, IsZeroGadget}, not, CachedRegion, Cell, }, @@ -31,7 +33,7 @@ impl ExecutionGadget for EndBlockGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::EndBlock; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let max_txs = cb.query_copy_cell(); let max_rws = cb.query_copy_cell(); let total_txs = cb.query_cell(); diff --git a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs index 207cf31c87..fcfad5f2cc 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::UpdateBalanceGadget, constraint_builder::{ - ConstraintBuilder, StepStateTransition, + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::{Delta, Same}, }, math_gadget::{ @@ -50,7 +50,7 @@ impl ExecutionGadget for EndTxGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::EndTx; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let is_persistent = cb.call_context(None, CallContextFieldTag::IsPersistent); diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index 7d16b76eef..2fc0f95c56 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -6,7 +6,7 @@ use crate::{ util::{ and, common_gadget::CommonErrorGadget, - constraint_builder::ConstraintBuilder, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, from_bytes, math_gadget::{IsEqualGadget, IsZeroGadget, LtGadget}, select, sum, CachedRegion, Cell, Word, @@ -40,7 +40,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorInvalidJump; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let dest_word = cb.query_word_rlc(); let dest_not_overflow = IsZeroGadget::construct(cb, sum::expr(&dest_word.cells[N_BYTES_PROGRAM_COUNTER..])); diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs index 4febed2a73..41b4e69026 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs @@ -3,7 +3,8 @@ use crate::evm_circuit::{ step::ExecutionState, table::{FixedTableTag, Lookup}, util::{ - common_gadget::CommonErrorGadget, constraint_builder::ConstraintBuilder, CachedRegion, Cell, + common_gadget::CommonErrorGadget, constraint_builder::EVMConstraintBuilder, CachedRegion, + Cell, }, witness::{Block, Call, ExecStep, Transaction}, }; @@ -24,7 +25,7 @@ impl ExecutionGadget for ErrorInvalidOpcodeGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorInvalidOpcode; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); cb.add_lookup( "Responsible opcode lookup", diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs index 4b133d7677..ce257fbbea 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::{CommonCallGadget, CommonErrorGadget}, - constraint_builder::ConstraintBuilder, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, math_gadget::{IsZeroGadget, LtGadget}, CachedRegion, Cell, }, @@ -41,7 +41,7 @@ impl ExecutionGadget for ErrorOOGCallGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasCall; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let is_call = IsZeroGadget::construct(cb, opcode.expr() - OpcodeId::CALL.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs index 717c91505c..e13d874b9b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs @@ -4,8 +4,10 @@ use crate::{ param::N_BYTES_GAS, step::ExecutionState, util::{ - common_gadget::CommonErrorGadget, constraint_builder::ConstraintBuilder, - math_gadget::LtGadget, CachedRegion, Cell, + common_gadget::CommonErrorGadget, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + math_gadget::LtGadget, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -28,7 +30,7 @@ impl ExecutionGadget for ErrorOOGConstantGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasConstant; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let gas_required = cb.query_cell(); diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs index cf6bc9638c..ed6da019aa 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::CommonErrorGadget, - constraint_builder::ConstraintBuilder, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, math_gadget::{ByteSizeGadget, LtGadget}, CachedRegion, Cell, Word, }, @@ -36,7 +36,7 @@ impl ExecutionGadget for ErrorOOGExpGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasEXP; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); cb.require_equal( diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs index b647d95a3b..075088eb09 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::CommonErrorGadget, - constraint_builder::ConstraintBuilder, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, math_gadget::LtGadget, memory_gadget::{MemoryAddressGadget, MemoryExpansionGadget}, CachedRegion, Cell, @@ -39,7 +39,7 @@ impl ExecutionGadget for ErrorOOGLogGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasLOG; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let mstart = cb.query_cell_phase2(); let msize = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs index d4f56ba227..b9511f0000 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::CommonErrorGadget, - constraint_builder::ConstraintBuilder, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, from_bytes, math_gadget::{IsZeroGadget, LtGadget}, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, @@ -49,7 +49,7 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasMemoryCopy; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); cb.require_in_set( "ErrorOutOfGasMemoryCopy opcode must be CALLDATACOPY, CODECOPY, EXTCODECOPY or RETURNDATACOPY", diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs index 0228957a15..8a0002e2e2 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs @@ -9,7 +9,7 @@ use crate::{ cal_sload_gas_cost_for_assignment, cal_sstore_gas_cost_for_assignment, CommonErrorGadget, SloadGasGadget, SstoreGasGadget, }, - constraint_builder::ConstraintBuilder, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, math_gadget::{LtGadget, PairSelectGadget}, or, select, CachedRegion, Cell, }, @@ -50,7 +50,7 @@ impl ExecutionGadget for ErrorOOGSloadSstoreGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasSloadSstore; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let is_sstore = PairSelectGadget::construct( diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs index 596885b855..e759be1692 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs @@ -4,7 +4,7 @@ use crate::{ param::{N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE}, step::ExecutionState, util::{ - constraint_builder::ConstraintBuilder, + constraint_builder::EVMConstraintBuilder, math_gadget::{IsEqualGadget, IsZeroGadget, RangeCheckGadget}, memory_gadget::{address_high, address_low, MemoryExpansionGadget}, CachedRegion, Cell, Word, @@ -41,7 +41,7 @@ impl ExecutionGadget for ErrorOOGStaticMemoryGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasStaticMemoryExpansion; // Support other OOG due to pure memory including CREATE, RETURN and REVERT - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); // Query address by a full word diff --git a/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs b/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs index 6993a60709..e5c106da5b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::CommonErrorGadget, - constraint_builder::ConstraintBuilder, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, from_bytes, math_gadget::{AddWordsGadget, IsZeroGadget, LtGadget}, not, or, sum, CachedRegion, Cell, @@ -38,7 +38,7 @@ impl ExecutionGadget for ErrorReturnDataOutOfBoundGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorReturnDataOutOfBound; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let memory_offset = cb.query_cell(); let data_offset = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs index 63111c4a10..e7b255c7ef 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs @@ -4,8 +4,8 @@ use crate::{ step::ExecutionState, table::{FixedTableTag, Lookup}, util::{ - common_gadget::CommonErrorGadget, constraint_builder::ConstraintBuilder, CachedRegion, - Cell, + common_gadget::CommonErrorGadget, constraint_builder::EVMConstraintBuilder, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -25,7 +25,7 @@ impl ExecutionGadget for ErrorStackGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorStack; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); cb.add_lookup( diff --git a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs index e891798b27..28c7416084 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs @@ -3,8 +3,10 @@ use crate::{ execution::ExecutionGadget, step::ExecutionState, util::{ - common_gadget::CommonErrorGadget, constraint_builder::ConstraintBuilder, - math_gadget::IsZeroGadget, sum, CachedRegion, Cell, Word as RLCWord, + common_gadget::CommonErrorGadget, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + math_gadget::IsZeroGadget, + sum, CachedRegion, Cell, Word as RLCWord, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -30,7 +32,7 @@ impl ExecutionGadget for ErrorWriteProtectionGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorWriteProtection; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let is_call = IsZeroGadget::construct(cb, opcode.expr() - OpcodeId::CALL.expr()); let gas_word = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/exp.rs b/zkevm-circuits/src/evm_circuit/execution/exp.rs index d83d50aa47..51347f3e36 100644 --- a/zkevm-circuits/src/evm_circuit/execution/exp.rs +++ b/zkevm-circuits/src/evm_circuit/execution/exp.rs @@ -7,7 +7,9 @@ use crate::evm_circuit::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition, + }, from_bytes, math_gadget::{ByteSizeGadget, IsEqualGadget, IsZeroGadget}, CachedRegion, Cell, Word, @@ -48,7 +50,7 @@ impl ExecutionGadget for ExponentiationGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::EXP; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); // Query RLC-encoded values for base, exponent and exponentiation, where: diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index 55d887a57a..01f1ac2a58 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -5,7 +5,8 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ - ConstraintBuilder, ReversionInfo, StepStateTransition, Transition, + ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, + Transition, }, from_bytes, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, @@ -43,7 +44,7 @@ impl ExecutionGadget for ExtcodecopyGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::EXTCODECOPY; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let external_address_word = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs index b15d727873..0d4b0ddd59 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ - ConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, + EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, }, from_bytes, select, CachedRegion, Cell, Word, }, @@ -33,7 +33,7 @@ impl ExecutionGadget for ExtcodehashGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::EXTCODEHASH; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let address_word = cb.query_word_rlc(); let address = from_bytes::expr(&address_word.cells[..N_BYTES_ACCOUNT_ADDRESS]); cb.stack_pop(address_word.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs index 3d1c99a690..e85deb09db 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs @@ -6,7 +6,8 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ - ConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, + ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, + Transition::Delta, }, from_bytes, math_gadget::IsZeroGadget, @@ -37,7 +38,7 @@ impl ExecutionGadget for ExtcodesizeGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::EXTCODESIZE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let address_word = cb.query_word_rlc(); let address = from_bytes::expr(&address_word.cells[..N_BYTES_ACCOUNT_ADDRESS]); cb.stack_pop(address_word.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/gas.rs b/zkevm-circuits/src/evm_circuit/execution/gas.rs index 7d8f8c37c2..4c9cb5dcd7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gas.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gas.rs @@ -5,7 +5,10 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, @@ -26,7 +29,7 @@ impl ExecutionGadget for GasGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::GAS; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { // The gas passed to a transaction is a 64-bit number. let gas_left = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs index 4d816bca78..ed4c749d90 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, @@ -28,7 +28,7 @@ impl ExecutionGadget for GasPriceGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::GASPRICE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { // Query gasprice value let gas_price = cb.query_cell_phase2(); diff --git a/zkevm-circuits/src/evm_circuit/execution/is_zero.rs b/zkevm-circuits/src/evm_circuit/execution/is_zero.rs index 33130cac30..a0d5e12520 100644 --- a/zkevm-circuits/src/evm_circuit/execution/is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/execution/is_zero.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, math_gadget, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, @@ -27,7 +27,7 @@ impl ExecutionGadget for IsZeroGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ISZERO; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let value = cb.query_cell_phase2(); diff --git a/zkevm-circuits/src/evm_circuit/execution/jump.rs b/zkevm-circuits/src/evm_circuit/execution/jump.rs index b4d858bb5a..ead6133a5d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jump.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ - ConstraintBuilder, StepStateTransition, + EVMConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, from_bytes, CachedRegion, RandomLinearCombination, @@ -29,7 +29,7 @@ impl ExecutionGadget for JumpGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::JUMP; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let destination = cb.query_word_rlc(); // Pop the value from the stack diff --git a/zkevm-circuits/src/evm_circuit/execution/jumpdest.rs b/zkevm-circuits/src/evm_circuit/execution/jumpdest.rs index 5cc57ead8a..57cf0edd67 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jumpdest.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jumpdest.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, CachedRegion, }, witness::{Block, Call, ExecStep, Transaction}, @@ -25,7 +25,7 @@ impl ExecutionGadget for JumpdestGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::JUMPDEST; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { // State transition let step_state_transition = StepStateTransition { program_counter: Delta(1.expr()), diff --git a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs index e8df2b822f..28d873b353 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ - ConstraintBuilder, StepStateTransition, + EVMConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, from_bytes, @@ -33,7 +33,7 @@ impl ExecutionGadget for JumpiGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::JUMPI; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let destination = cb.query_word_rlc(); let phase2_condition = cb.query_cell_phase2(); diff --git a/zkevm-circuits/src/evm_circuit/execution/logs.rs b/zkevm-circuits/src/evm_circuit/execution/logs.rs index 6e4889022a..d3d0fe2ca4 100644 --- a/zkevm-circuits/src/evm_circuit/execution/logs.rs +++ b/zkevm-circuits/src/evm_circuit/execution/logs.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ - ConstraintBuilder, StepStateTransition, + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, memory_gadget::{MemoryAddressGadget, MemoryExpansionGadget}, @@ -46,7 +46,7 @@ impl ExecutionGadget for LogGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::LOG; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let mstart = cb.query_cell_phase2(); let msize = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/memory.rs b/zkevm-circuits/src/evm_circuit/execution/memory.rs index 8dfa64e01d..0adc47f0ad 100644 --- a/zkevm-circuits/src/evm_circuit/execution/memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/memory.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ - ConstraintBuilder, StepStateTransition, + EVMConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, from_bytes, @@ -36,7 +36,7 @@ impl ExecutionGadget for MemoryGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::MEMORY; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); // In successful case the address must be in 5 bytes diff --git a/zkevm-circuits/src/evm_circuit/execution/msize.rs b/zkevm-circuits/src/evm_circuit/execution/msize.rs index 41d77eb2f5..37d04e91fe 100644 --- a/zkevm-circuits/src/evm_circuit/execution/msize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/msize.rs @@ -5,7 +5,10 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, @@ -27,7 +30,7 @@ impl ExecutionGadget for MsizeGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::MSIZE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let value = cb.query_word_rlc(); // memory_size is limited to 64 bits so we only consider 8 bytes diff --git a/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs b/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs index bb0bf1a971..e38ffd9d80 100644 --- a/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs @@ -5,7 +5,10 @@ use crate::{ util::{ self, common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, math_gadget::{IsZeroGadget, LtWordGadget, MulAddWordsGadget}, select, sum, CachedRegion, }, @@ -40,7 +43,7 @@ impl ExecutionGadget for MulDivModGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::MUL_DIV_MOD; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let is_mul = (OpcodeId::DIV.expr() - opcode.expr()) diff --git a/zkevm-circuits/src/evm_circuit/execution/mulmod.rs b/zkevm-circuits/src/evm_circuit/execution/mulmod.rs index c31abab8d0..ad146ca1a6 100644 --- a/zkevm-circuits/src/evm_circuit/execution/mulmod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/mulmod.rs @@ -5,7 +5,10 @@ use crate::{ util::{ self, common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, math_gadget::{IsZeroGadget, LtWordGadget, ModGadget, MulAddWords512Gadget}, sum, CachedRegion, }, @@ -41,7 +44,7 @@ impl ExecutionGadget for MulModGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::MULMOD; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let a = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/not.rs b/zkevm-circuits/src/evm_circuit/execution/not.rs index 5590f0e6bd..7a076021b3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/not.rs +++ b/zkevm-circuits/src/evm_circuit/execution/not.rs @@ -5,7 +5,7 @@ use crate::{ table::{FixedTableTag, Lookup}, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, CachedRegion, Word, }, witness::{Block, Call, ExecStep, Transaction}, @@ -27,7 +27,7 @@ impl ExecutionGadget for NotGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::NOT; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let input = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/origin.rs b/zkevm-circuits/src/evm_circuit/execution/origin.rs index be2c3edefa..f47f186463 100644 --- a/zkevm-circuits/src/evm_circuit/execution/origin.rs +++ b/zkevm-circuits/src/evm_circuit/execution/origin.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, CachedRegion, Cell, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, @@ -29,7 +29,7 @@ impl ExecutionGadget for OriginGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ORIGIN; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let origin = cb.query_word_rlc::(); // Lookup in call_ctx the TxId diff --git a/zkevm-circuits/src/evm_circuit/execution/pc.rs b/zkevm-circuits/src/evm_circuit/execution/pc.rs index 14fc0cee9f..9180cb5452 100644 --- a/zkevm-circuits/src/evm_circuit/execution/pc.rs +++ b/zkevm-circuits/src/evm_circuit/execution/pc.rs @@ -5,7 +5,10 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, @@ -27,7 +30,7 @@ impl ExecutionGadget for PcGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::PC; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let value = cb.query_word_rlc(); // program_counter is limited to 64 bits so we only consider 8 bytes diff --git a/zkevm-circuits/src/evm_circuit/execution/pop.rs b/zkevm-circuits/src/evm_circuit/execution/pop.rs index 3b92858ce4..77c4ad3c3f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/pop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/pop.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, @@ -26,7 +26,7 @@ impl ExecutionGadget for PopGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::POP; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let phase2_value = cb.query_cell_phase2(); // Pop the value from the stack diff --git a/zkevm-circuits/src/evm_circuit/execution/push.rs b/zkevm-circuits/src/evm_circuit/execution/push.rs index f2c28954bb..d21549b1d7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/push.rs +++ b/zkevm-circuits/src/evm_circuit/execution/push.rs @@ -4,7 +4,10 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, sum, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, @@ -27,7 +30,7 @@ impl ExecutionGadget for PushGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::PUSH; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let value = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs index cf5d0e8d2c..9c20e3ee1e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs +++ b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::RestoreContextGadget, constraint_builder::{ - ConstraintBuilder, ReversionInfo, StepStateTransition, + ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::{Delta, To}, }, math_gadget::{IsZeroGadget, MinMaxGadget}, @@ -51,7 +51,7 @@ impl ExecutionGadget for ReturnRevertGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::RETURN_REVERT; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); cb.opcode_lookup(opcode.expr(), 1.expr()); diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs index 4b4392ff2a..d8af064cf6 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs @@ -6,7 +6,7 @@ use crate::{ util::{ common_gadget::SameContextGadget, constraint_builder::{ - ConstraintBuilder, StepStateTransition, + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, from_bytes, @@ -57,7 +57,7 @@ impl ExecutionGadget for ReturnDataCopyGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::RETURNDATACOPY; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let dest_offset = cb.query_cell_phase2(); diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs index 82bae82f6e..51aac27a97 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs @@ -5,7 +5,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, CachedRegion, RandomLinearCombination, }, witness::{Block, Call, ExecStep, Transaction}, @@ -28,7 +28,7 @@ impl ExecutionGadget for ReturnDataSizeGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::RETURNDATASIZE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); // Add lookup constraint in the call context for the returndatasize field. diff --git a/zkevm-circuits/src/evm_circuit/execution/sar.rs b/zkevm-circuits/src/evm_circuit/execution/sar.rs index ed339be385..97e1e2c259 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sar.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sar.rs @@ -6,7 +6,10 @@ use crate::{ table::{FixedTableTag, Lookup}, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, from_bytes, math_gadget::{IsEqualGadget, IsZeroGadget, LtGadget}, select, sum, CachedRegion, Cell, Word, @@ -71,7 +74,7 @@ impl ExecutionGadget for SarGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SAR; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let shift = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs b/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs index ac4682f492..95a8b451df 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs @@ -4,7 +4,10 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, math_gadget::{AbsWordGadget, IsZeroGadget, LtGadget, LtWordGadget, MulAddWordsGadget}, select, sum, CachedRegion, }, @@ -36,7 +39,7 @@ impl ExecutionGadget for SignedDivModGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SDIV_SMOD; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let is_sdiv = (OpcodeId::SMOD.expr() - opcode.expr()) * F::from(2).invert().unwrap(); diff --git a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs index 8c0863492e..584fcee949 100644 --- a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, @@ -28,7 +28,7 @@ impl ExecutionGadget for SelfbalanceGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SELFBALANCE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let callee_address = cb.call_context(None, CallContextFieldTag::CalleeAddress); let phase2_self_balance = cb.query_cell_phase2(); diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index 761f37c3bf..3f8c11f714 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -8,7 +8,9 @@ use crate::evm_circuit::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition, + }, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, rlc, CachedRegion, Cell, Word, }, @@ -33,7 +35,7 @@ impl ExecutionGadget for Sha3Gadget { const NAME: &'static str = "SHA3"; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let offset = cb.query_cell_phase2(); diff --git a/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs b/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs index dbecca2252..409114b3cf 100644 --- a/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs +++ b/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs @@ -6,7 +6,10 @@ use crate::{ util::{ self, common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, from_bytes, math_gadget::{IsZeroGadget, LtWordGadget, MulAddWordsGadget}, sum, CachedRegion, Cell, @@ -51,7 +54,7 @@ impl ExecutionGadget for ShlShrGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SHL_SHR; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let is_shl = OpcodeId::SHR.expr() - opcode.expr(); let is_shr = 1.expr() - is_shl.expr(); diff --git a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs index 52eb0f9ec8..11284033a1 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, from_bytes, math_gadget::{ComparisonGadget, IsEqualGadget, LtGadget}, select, CachedRegion, Cell, Word, @@ -39,7 +39,7 @@ impl ExecutionGadget for SignedComparatorGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SCMP; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let a = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/execution/signextend.rs b/zkevm-circuits/src/evm_circuit/execution/signextend.rs index 0b4f28f6a2..edd543d0ee 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signextend.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signextend.rs @@ -6,7 +6,10 @@ use crate::{ util::{ and, common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{ + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, + Transition::Delta, + }, math_gadget::{IsEqualGadget, IsZeroGadget}, rlc, select, sum, CachedRegion, Cell, Word, }, @@ -35,7 +38,7 @@ impl ExecutionGadget for SignextendGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SIGNEXTEND; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let index = cb.query_word_rlc(); let value = cb.query_word_rlc(); let sign_byte = cb.query_cell(); diff --git a/zkevm-circuits/src/evm_circuit/execution/sload.rs b/zkevm-circuits/src/evm_circuit/execution/sload.rs index 4f9622bd33..9d3f623909 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sload.rs @@ -5,7 +5,7 @@ use crate::{ util::{ common_gadget::{SameContextGadget, SloadGasGadget}, constraint_builder::{ - ConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, + EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, }, CachedRegion, Cell, }, @@ -34,7 +34,7 @@ impl ExecutionGadget for SloadGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SLOAD; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let tx_id = cb.call_context(None, CallContextFieldTag::TxId); diff --git a/zkevm-circuits/src/evm_circuit/execution/sstore.rs b/zkevm-circuits/src/evm_circuit/execution/sstore.rs index 8aee917e5c..7446e17938 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sstore.rs @@ -6,7 +6,8 @@ use crate::{ util::{ common_gadget::{SameContextGadget, SstoreGasGadget}, constraint_builder::{ - ConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta, + ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, + Transition::Delta, }, math_gadget::{IsEqualGadget, IsZeroGadget, LtGadget}, not, CachedRegion, Cell, @@ -47,7 +48,7 @@ impl ExecutionGadget for SstoreGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SSTORE; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let tx_id = cb.call_context(None, CallContextFieldTag::TxId); @@ -244,7 +245,7 @@ pub(crate) struct SstoreTxRefundGadget { impl SstoreTxRefundGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, tx_refund_old: Cell, value: Cell, value_prev: Cell, diff --git a/zkevm-circuits/src/evm_circuit/execution/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index d58be6cf9d..9045ca94ac 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -5,7 +5,7 @@ use crate::{ util::{ common_gadget::RestoreContextGadget, constraint_builder::{ - ConstraintBuilder, StepStateTransition, + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::{Delta, Same}, }, math_gadget::IsZeroGadget, @@ -33,7 +33,7 @@ impl ExecutionGadget for StopGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::STOP; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let code_length = cb.query_cell(); cb.bytecode_length(cb.curr.state.code_hash.expr(), code_length.expr()); let is_out_of_range = IsZeroGadget::construct( diff --git a/zkevm-circuits/src/evm_circuit/execution/swap.rs b/zkevm-circuits/src/evm_circuit/execution/swap.rs index 5127fd2ad1..951d8922f7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/swap.rs +++ b/zkevm-circuits/src/evm_circuit/execution/swap.rs @@ -4,7 +4,7 @@ use crate::{ step::ExecutionState, util::{ common_gadget::SameContextGadget, - constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta}, + constraint_builder::{EVMConstraintBuilder, StepStateTransition, Transition::Delta}, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, @@ -25,7 +25,7 @@ impl ExecutionGadget for SwapGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::SWAP; - fn configure(cb: &mut ConstraintBuilder) -> Self { + fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); let phase2_values = [cb.query_cell_phase2(), cb.query_cell_phase2()]; diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 973987caed..fe2a83d81a 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -1,4 +1,5 @@ use super::{ + constraint_builder::ConstrainBuilderCommon, from_bytes, math_gadget::{IsEqualGadget, IsZeroGadget}, memory_gadget::{MemoryAddressGadget, MemoryExpansionGadget}, @@ -11,7 +12,7 @@ use crate::{ table::{FixedTableTag, Lookup}, util::{ constraint_builder::{ - ConstraintBuilder, ReversionInfo, StepStateTransition, + EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::{Delta, Same, To}, }, math_gadget::{AddWordsGadget, RangeCheckGadget}, @@ -40,7 +41,7 @@ pub(crate) struct SameContextGadget { impl SameContextGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, opcode: Cell, step_state_transition: StepStateTransition, ) -> Self { @@ -102,7 +103,7 @@ pub(crate) struct RestoreContextGadget { impl RestoreContextGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, is_success: Expression, // Expression for the number of rw lookups that occur after this gadget is constructed. subsequent_rw_lookups: Expression, @@ -265,7 +266,7 @@ impl UpdateBalanceGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, address: Expression, updates: Vec>, reversion_info: Option<&mut ReversionInfo>, @@ -360,7 +361,7 @@ pub(crate) struct TransferWithGasFeeGadget { impl TransferWithGasFeeGadget { #[allow(clippy::too_many_arguments)] pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, sender_address: Expression, receiver_address: Expression, receiver_exists: Expression, @@ -491,7 +492,7 @@ pub(crate) struct TransferGadget { impl TransferGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, sender_address: Expression, receiver_address: Expression, receiver_exists: Expression, @@ -594,7 +595,7 @@ pub(crate) struct CommonCallGadget { impl CommonCallGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, is_call: Expression, is_callcode: Expression, is_delegatecall: Expression, @@ -798,7 +799,7 @@ pub(crate) struct SloadGasGadget { } impl SloadGasGadget { - pub(crate) fn construct(_cb: &mut ConstraintBuilder, is_warm: Expression) -> Self { + pub(crate) fn construct(_cb: &mut EVMConstraintBuilder, is_warm: Expression) -> Self { let gas_cost = select::expr( is_warm.expr(), GasCost::WARM_ACCESS.expr(), @@ -828,7 +829,7 @@ pub(crate) struct SstoreGasGadget { impl SstoreGasGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, value: Cell, value_prev: Cell, original_value: Cell, @@ -949,7 +950,7 @@ pub(crate) struct CommonErrorGadget { impl CommonErrorGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, opcode: Expression, rw_counter_delta: Expression, ) -> Self { diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index da85efa7c7..a9f0523e0c 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -88,7 +88,7 @@ impl StepStateTransition { /// ReversionInfo counts `rw_counter` of reversion for gadgets, by tracking how /// many reversions that have been used. Gadgets should call -/// [`ConstraintBuilder::reversion_info`] to get [`ReversionInfo`] with +/// [`EVMConstraintBuilder::reversion_info`] to get [`ReversionInfo`] with /// `reversible_write_counter` initialized at current tracking one if no /// `call_id` is specified, then pass it as mutable reference when doing state /// write. @@ -141,40 +141,22 @@ impl ReversionInfo { } } -#[derive(Default)] -pub struct BaseConstraintBuilder { - pub constraints: Vec<(&'static str, Expression)>, - pub max_degree: usize, - pub condition: Option>, -} - -impl BaseConstraintBuilder { - pub(crate) fn new(max_degree: usize) -> Self { - BaseConstraintBuilder { - constraints: Vec::new(), - max_degree, - condition: None, - } - } +pub(crate) trait ConstrainBuilderCommon { + fn add_constraint(&mut self, name: &'static str, constraint: Expression); - pub(crate) fn require_zero(&mut self, name: &'static str, constraint: Expression) { + fn require_zero(&mut self, name: &'static str, constraint: Expression) { self.add_constraint(name, constraint); } - pub(crate) fn require_equal( - &mut self, - name: &'static str, - lhs: Expression, - rhs: Expression, - ) { + fn require_equal(&mut self, name: &'static str, lhs: Expression, rhs: Expression) { self.add_constraint(name, lhs - rhs); } - pub(crate) fn require_boolean(&mut self, name: &'static str, value: Expression) { + fn require_boolean(&mut self, name: &'static str, value: Expression) { self.add_constraint(name, value.clone() * (1.expr() - value)); } - pub(crate) fn require_in_set( + fn require_in_set( &mut self, name: &'static str, value: Expression, @@ -187,6 +169,40 @@ impl BaseConstraintBuilder { ); } + fn add_constraints(&mut self, constraints: Vec<(&'static str, Expression)>) { + for (name, constraint) in constraints { + self.add_constraint(name, constraint); + } + } +} + +#[derive(Default)] +pub struct BaseConstraintBuilder { + pub constraints: Vec<(&'static str, Expression)>, + pub max_degree: usize, + pub condition: Option>, +} + +impl ConstrainBuilderCommon for BaseConstraintBuilder { + fn add_constraint(&mut self, name: &'static str, constraint: Expression) { + let constraint = match &self.condition { + Some(condition) => condition.clone() * constraint, + None => constraint, + }; + self.validate_degree(constraint.degree(), name); + self.constraints.push((name, constraint)); + } +} + +impl BaseConstraintBuilder { + pub(crate) fn new(max_degree: usize) -> Self { + BaseConstraintBuilder { + constraints: Vec::new(), + max_degree, + condition: None, + } + } + pub(crate) fn condition( &mut self, condition: Expression, @@ -202,21 +218,6 @@ impl BaseConstraintBuilder { ret } - pub(crate) fn add_constraints(&mut self, constraints: Vec<(&'static str, Expression)>) { - for (name, constraint) in constraints { - self.add_constraint(name, constraint); - } - } - - pub(crate) fn add_constraint(&mut self, name: &'static str, constraint: Expression) { - let constraint = match &self.condition { - Some(condition) => condition.clone() * constraint, - None => constraint, - }; - self.validate_degree(constraint.degree(), name); - self.constraints.push((name, constraint)); - } - pub(crate) fn validate_degree(&self, degree: usize, name: &'static str) { if self.max_degree > 0 { debug_assert!( @@ -263,7 +264,7 @@ pub(crate) struct Constraints { pub(crate) not_step_last: Vec<(&'static str, Expression)>, } -pub(crate) struct ConstraintBuilder<'a, F> { +pub(crate) struct EVMConstraintBuilder<'a, F> { pub max_degree: usize, pub(crate) curr: Step, pub(crate) next: Step, @@ -280,7 +281,20 @@ pub(crate) struct ConstraintBuilder<'a, F> { stored_expressions: Vec>, } -impl<'a, F: Field> ConstraintBuilder<'a, F> { +impl<'a, F: Field> ConstrainBuilderCommon for EVMConstraintBuilder<'a, F> { + fn add_constraint(&mut self, name: &'static str, constraint: Expression) { + let constraint = self.split_expression( + name, + constraint * self.condition_expr(), + MAX_DEGREE - IMPLICIT_DEGREE, + ); + + self.validate_degree(constraint.degree(), name); + self.push_constraint(name, constraint); + } +} + +impl<'a, F: Field> EVMConstraintBuilder<'a, F> { pub(crate) fn new( curr: Step, next: Step, @@ -443,38 +457,6 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { self.word_rlc((*EMPTY_CODE_HASH_LE).map(|byte| byte.expr())) } - // Common - - pub(crate) fn require_zero(&mut self, name: &'static str, constraint: Expression) { - self.add_constraint(name, constraint); - } - - pub(crate) fn require_equal( - &mut self, - name: &'static str, - lhs: Expression, - rhs: Expression, - ) { - self.add_constraint(name, lhs - rhs); - } - - pub(crate) fn require_boolean(&mut self, name: &'static str, value: Expression) { - self.add_constraint(name, value.clone() * (1.expr() - value)); - } - - pub(crate) fn require_in_set( - &mut self, - name: &'static str, - value: Expression, - set: Vec>, - ) { - self.add_constraint( - name, - set.iter() - .fold(1.expr(), |acc, item| acc * (value.clone() - item.clone())), - ); - } - pub(crate) fn require_next_state(&mut self, execution_state: ExecutionState) { let next_state = self.next.execution_state_selector([execution_state]); self.add_constraint( @@ -1378,23 +1360,6 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { ret } - pub(crate) fn add_constraints(&mut self, constraints: Vec<(&'static str, Expression)>) { - for (name, constraint) in constraints { - self.add_constraint(name, constraint); - } - } - - pub(crate) fn add_constraint(&mut self, name: &'static str, constraint: Expression) { - let constraint = self.split_expression( - name, - constraint * self.condition_expr(), - MAX_DEGREE - IMPLICIT_DEGREE, - ); - - self.validate_degree(constraint.degree(), name); - self.push_constraint(name, constraint); - } - /// TODO: Doc fn constraint_at_location( &mut self, diff --git a/zkevm-circuits/src/evm_circuit/util/instrumentation.rs b/zkevm-circuits/src/evm_circuit/util/instrumentation.rs index 103d34d202..ec744060cd 100644 --- a/zkevm-circuits/src/evm_circuit/util/instrumentation.rs +++ b/zkevm-circuits/src/evm_circuit/util/instrumentation.rs @@ -1,7 +1,7 @@ use crate::evm_circuit::{ step::ExecutionState, table::Table, - util::{constraint_builder::ConstraintBuilder, CellType}, + util::{constraint_builder::EVMConstraintBuilder, CellType}, }; use halo2_proofs::arithmetic::FieldExt; use itertools::Itertools; @@ -23,7 +23,7 @@ impl Instrument { pub(crate) fn on_gadget_built( &mut self, execution_state: ExecutionState, - cb: &ConstraintBuilder<'_, F>, + cb: &EVMConstraintBuilder, ) { let sizes = cb .curr diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/abs_word.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/abs_word.rs index d92ca58822..e7bbe5dc8e 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/abs_word.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/abs_word.rs @@ -1,6 +1,10 @@ use crate::{ evm_circuit::util::{ - self, constraint_builder::ConstraintBuilder, from_bytes, math_gadget::*, CachedRegion, + self, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + from_bytes, + math_gadget::*, + CachedRegion, }, util::Expr, }; @@ -23,7 +27,7 @@ pub(crate) struct AbsWordGadget { } impl AbsWordGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder) -> Self { let x = cb.query_word_rlc(); let x_abs = cb.query_word_rlc(); let sum = cb.query_word_rlc(); @@ -100,6 +104,7 @@ impl AbsWordGadget { #[cfg(test)] mod tests { use super::{super::test_util::*, *}; + use crate::evm_circuit::util::constraint_builder::ConstrainBuilderCommon; use eth_types::{Word, U256}; use halo2_proofs::{halo2curves::bn256::Fr, plonk::Error}; @@ -110,7 +115,7 @@ mod tests { } impl MathGadgetContainer for AbsWordGadgetContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let absword_gadget = AbsWordGadget::::construct(cb); cb.require_equal( "is_neg is correct", diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/add_words.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/add_words.rs index 87673f208b..704fd60fef 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/add_words.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/add_words.rs @@ -1,7 +1,8 @@ use crate::{ evm_circuit::util::{ - self, constraint_builder::ConstraintBuilder, from_bytes, pow_of_two_expr, split_u256, sum, - CachedRegion, Cell, + self, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + from_bytes, pow_of_two_expr, split_u256, sum, CachedRegion, Cell, }, util::Expr, }; @@ -22,7 +23,7 @@ impl AddWordsGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, addends: [util::Word; N_ADDENDS], sum: util::Word, ) -> Self { @@ -167,7 +168,7 @@ mod tests { impl MathGadgetContainer for AddWordsTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let addends = [(); N_ADDENDS].map(|_| cb.query_word_rlc()); let sum = cb.query_word_rlc(); let addwords_gadget = AddWordsGadget::::construct( diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs index 8e3ca5965f..a0bb5a9c25 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs @@ -1,6 +1,7 @@ use crate::{ evm_circuit::util::{ - constraint_builder::ConstraintBuilder, transpose_val_ret, CachedRegion, Cell, CellType, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + transpose_val_ret, CachedRegion, Cell, CellType, }, util::Expr, }; @@ -17,7 +18,7 @@ pub struct BatchedIsZeroGadget { } impl BatchedIsZeroGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, values: [Expression; N]) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, values: [Expression; N]) -> Self { let max_values_phase = values .iter() .map(CellType::expr_phase) @@ -97,7 +98,7 @@ mod tests { } impl MathGadgetContainer for IsZeroGadgetTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let nums = [(); N].map(|_| cb.query_cell()); let z_gadget = BatchedIsZeroGadget::::construct( cb, diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/binary_number.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/binary_number.rs index 6484ab4a6e..d872bfc6b7 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/binary_number.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/binary_number.rs @@ -5,7 +5,10 @@ use halo2_proofs::{ plonk::{Error, Expression}, }; -use crate::evm_circuit::util::{constraint_builder::ConstraintBuilder, CachedRegion, Cell}; +use crate::evm_circuit::util::{ + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + CachedRegion, Cell, +}; #[derive(Clone, Debug)] pub struct BinaryNumberGadget { @@ -13,7 +16,7 @@ pub struct BinaryNumberGadget { } impl BinaryNumberGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, value: Expression) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, value: Expression) -> Self { let bits = array_init::array_init(|_| cb.query_bool()); // the binary representation of value must be correct. diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs index db1b81ffaf..f02fefb15f 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs @@ -1,7 +1,10 @@ use crate::{ evm_circuit::{ param::N_BYTES_WORD, - util::{constraint_builder::ConstraintBuilder, sum, CachedRegion, Cell}, + util::{ + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + sum, CachedRegion, Cell, + }, }, util::Expr, }; @@ -25,7 +28,7 @@ pub(crate) struct ByteSizeGadget { impl ByteSizeGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, values: [Expression; N_BYTES_WORD], ) -> Self { let most_significant_nonzero_byte_index = [(); N_BYTES_WORD + 1].map(|()| cb.query_bool()); @@ -123,7 +126,7 @@ mod tests { } impl MathGadgetContainer for ByteSizeGadgetContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let value_rlc = cb.query_word_rlc(); let bytesize_gadget = ByteSizeGadget::::construct( cb, diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/cmp_words.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/cmp_words.rs index 758484a65b..1a6f657bf1 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/cmp_words.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/cmp_words.rs @@ -1,6 +1,6 @@ use crate::{ evm_circuit::util::{ - self, constraint_builder::ConstraintBuilder, from_bytes, math_gadget::*, select, + self, constraint_builder::EVMConstraintBuilder, from_bytes, math_gadget::*, select, CachedRegion, }, util::Expr, @@ -19,7 +19,7 @@ pub(crate) struct CmpWordsGadget { impl CmpWordsGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, a: &util::Word, b: &util::Word, ) -> Self { @@ -86,6 +86,7 @@ impl CmpWordsGadget { #[cfg(test)] mod tests { use super::{test_util::*, *}; + use crate::evm_circuit::util::constraint_builder::ConstrainBuilderCommon; use eth_types::Word; use halo2_proofs::{halo2curves::bn256::Fr, plonk::Error}; @@ -100,7 +101,7 @@ mod tests { impl MathGadgetContainer for CmpWordGadgetTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_word_rlc(); let b = cb.query_word_rlc(); let cmp_gadget = CmpWordsGadget::::construct(cb, &a, &b); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/comparison.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/comparison.rs index fccd872772..5568ec54c4 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/comparison.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/comparison.rs @@ -1,5 +1,5 @@ use crate::evm_circuit::util::{ - constraint_builder::ConstraintBuilder, math_gadget::*, sum, CachedRegion, + constraint_builder::EVMConstraintBuilder, math_gadget::*, sum, CachedRegion, }; use eth_types::Field; use halo2_proofs::plonk::{Error, Expression}; @@ -17,7 +17,7 @@ pub struct ComparisonGadget { impl ComparisonGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, lhs: Expression, rhs: Expression, ) -> Self { @@ -51,7 +51,7 @@ impl ComparisonGadget { #[cfg(test)] mod tests { use super::{test_util::*, *}; - use crate::evm_circuit::util::Cell; + use crate::evm_circuit::util::{constraint_builder::ConstrainBuilderCommon, Cell}; use eth_types::*; use halo2_proofs::{halo2curves::bn256::Fr, plonk::Error}; @@ -66,7 +66,7 @@ mod tests { impl MathGadgetContainer for ComparisonTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_cell(); let b = cb.query_cell(); let cmp_gadget = ComparisonGadget::::construct(cb, a.expr(), b.expr()); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/constant_division.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/constant_division.rs index 824c035ef2..838cc585c2 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/constant_division.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/constant_division.rs @@ -1,7 +1,8 @@ use crate::{ evm_circuit::util::{ - constraint_builder::ConstraintBuilder, math_gadget::*, transpose_val_ret, CachedRegion, - Cell, CellType, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + math_gadget::*, + transpose_val_ret, CachedRegion, Cell, CellType, }, util::Expr, }; @@ -26,7 +27,7 @@ pub struct ConstantDivisionGadget { impl ConstantDivisionGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, numerator: Expression, denominator: u64, ) -> Self { @@ -125,7 +126,7 @@ mod tests { > MathGadgetContainer for ConstantDivisionTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_cell(); let constdiv_gadget = ConstantDivisionGadget::::construct(cb, a.expr(), DENOMINATOR); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal.rs index 1b5bb41128..1c472181c6 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal.rs @@ -1,5 +1,5 @@ use crate::evm_circuit::util::{ - constraint_builder::ConstraintBuilder, math_gadget::*, transpose_val_ret, CachedRegion, + constraint_builder::EVMConstraintBuilder, math_gadget::*, transpose_val_ret, CachedRegion, }; use eth_types::Field; use halo2_proofs::{ @@ -15,7 +15,7 @@ pub struct IsEqualGadget { impl IsEqualGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, lhs: Expression, rhs: Expression, ) -> Self { @@ -55,7 +55,9 @@ impl IsEqualGadget { #[cfg(test)] mod tests { use super::{test_util::*, *}; - use crate::evm_circuit::util::{CachedRegion, Cell}; + use crate::evm_circuit::util::{ + constraint_builder::ConstrainBuilderCommon, CachedRegion, Cell, + }; use eth_types::*; use halo2_proofs::{halo2curves::bn256::Fr, plonk::Error}; @@ -68,7 +70,7 @@ mod tests { } impl MathGadgetContainer for IsEqualGadgetTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_cell(); let b = cb.query_cell(); let eq_gadget = IsEqualGadget::::construct(cb, a.expr(), b.expr()); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs index 1f0de17ca3..85a921bd8e 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs @@ -1,6 +1,7 @@ use crate::{ evm_circuit::util::{ - constraint_builder::ConstraintBuilder, transpose_val_ret, CachedRegion, Cell, CellType, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + transpose_val_ret, CachedRegion, Cell, CellType, }, util::Expr, }; @@ -18,7 +19,7 @@ pub struct IsZeroGadget { } impl IsZeroGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, value: Expression) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, value: Expression) -> Self { let inverse = cb.query_cell_with_type(CellType::storage_for_expr(&value)); let is_zero = 1.expr() - (value.clone() * inverse.expr()); @@ -66,8 +67,13 @@ impl IsZeroGadget { #[cfg(test)] mod tests { + use crate::{ + evm_circuit::util::{constraint_builder::ConstrainBuilderCommon, Cell}, + util::Expr, + }; + use super::{super::test_util::*, *}; - use crate::{evm_circuit::util::Cell, util::Expr}; + use eth_types::{ToScalar, Word}; use halo2_proofs::{halo2curves::bn256::Fr, plonk::Error}; @@ -79,7 +85,7 @@ mod tests { } impl MathGadgetContainer for IsZeroGadgetTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let n = cb.query_cell(); let z_gadget = IsZeroGadget::::construct(cb, n.expr()); cb.require_equal("Input is zero", z_gadget.expr(), 1.expr()); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs index e43af2a23f..ef5ca9afce 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs @@ -1,7 +1,7 @@ use crate::{ evm_circuit::util::{ - constraint_builder::ConstraintBuilder, from_bytes, pow_of_two, transpose_val_ret, - CachedRegion, Cell, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + from_bytes, pow_of_two, transpose_val_ret, CachedRegion, Cell, }, util::Expr, }; @@ -30,7 +30,7 @@ pub struct LtGadget { impl LtGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, lhs: Expression, rhs: Expression, ) -> Self { @@ -115,7 +115,7 @@ mod tests { } impl MathGadgetContainer for LtGadgetTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_cell(); let b = cb.query_cell(); let lt_gadget = LtGadget::::construct(cb, a.expr(), b.expr()); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs index 04f674c97a..601d9a88e7 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs @@ -1,5 +1,5 @@ use crate::evm_circuit::util::{ - self, constraint_builder::ConstraintBuilder, from_bytes, math_gadget::*, split_u256, + self, constraint_builder::EVMConstraintBuilder, from_bytes, math_gadget::*, split_u256, CachedRegion, }; use eth_types::{Field, Word}; @@ -15,7 +15,7 @@ pub struct LtWordGadget { impl LtWordGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, lhs: &util::Word, rhs: &util::Word, ) -> Self { @@ -67,6 +67,8 @@ impl LtWordGadget { #[cfg(test)] mod tests { + use crate::evm_circuit::util::constraint_builder::ConstrainBuilderCommon; + use super::{test_util::*, *}; use eth_types::*; use halo2_proofs::{halo2curves::bn256::Fr, plonk::Error}; @@ -80,7 +82,7 @@ mod tests { } impl MathGadgetContainer for LtWordTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_word_rlc(); let b = cb.query_word_rlc(); let ltword_gadget = LtWordGadget::::construct(cb, &a, &b); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max.rs index a5bb9ffdfb..e17f9c7b39 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/min_max.rs @@ -1,5 +1,6 @@ use crate::evm_circuit::util::{ - constraint_builder::ConstraintBuilder, math_gadget::*, select, transpose_val_ret, CachedRegion, + constraint_builder::EVMConstraintBuilder, math_gadget::*, select, transpose_val_ret, + CachedRegion, }; use eth_types::Field; use halo2_proofs::{ @@ -18,7 +19,7 @@ pub struct MinMaxGadget { impl MinMaxGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, lhs: Expression, rhs: Expression, ) -> Self { @@ -69,7 +70,7 @@ impl MinMaxGadget { #[cfg(test)] mod tests { use super::{test_util::*, *}; - use crate::evm_circuit::util::Cell; + use crate::evm_circuit::util::{constraint_builder::ConstrainBuilderCommon, Cell}; use eth_types::{ToScalar, Word}; use halo2_proofs::{halo2curves::bn256::Fr, plonk::Error}; @@ -84,7 +85,7 @@ mod tests { impl MathGadgetContainer for MinMaxTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_cell(); let b = cb.query_cell(); let minmax_gadget = MinMaxGadget::::construct(cb, a.expr(), b.expr()); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/modulo.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/modulo.rs index 2d03e1c63e..d4b65f20b0 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/modulo.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/modulo.rs @@ -1,6 +1,9 @@ use crate::{ evm_circuit::util::{ - self, constraint_builder::ConstraintBuilder, math_gadget::*, sum, CachedRegion, + self, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + math_gadget::*, + sum, CachedRegion, }, util::Expr, }; @@ -27,7 +30,7 @@ pub(crate) struct ModGadget { lt: LtWordGadget, } impl ModGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, words: [&util::Word; 3]) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, words: [&util::Word; 3]) -> Self { let (a, n, r) = (words[0], words[1], words[2]); let k = cb.query_word_rlc(); let a_or_zero = cb.query_word_rlc(); @@ -113,7 +116,7 @@ mod tests { } impl MathGadgetContainer for ModGadgetTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_word_rlc(); let n = cb.query_word_rlc(); let r = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs index 27792a9abc..1a212906a7 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs @@ -1,7 +1,8 @@ use crate::{ evm_circuit::util::{ - self, constraint_builder::ConstraintBuilder, from_bytes, pow_of_two_expr, split_u256, - split_u256_limb64, CachedRegion, Cell, + self, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + from_bytes, pow_of_two_expr, split_u256, split_u256_limb64, CachedRegion, Cell, }, util::Expr, }; @@ -49,7 +50,7 @@ pub(crate) struct MulAddWordsGadget { } impl MulAddWordsGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, words: [&util::Word; 4]) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, words: [&util::Word; 4]) -> Self { let (a, b, c, d) = (words[0], words[1], words[2], words[3]); let carry_lo = cb.query_bytes(); let carry_hi = cb.query_bytes(); @@ -165,7 +166,7 @@ mod tests { } impl MathGadgetContainer for MulAddGadgetContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_word_rlc(); let b = cb.query_word_rlc(); let c = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words512.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words512.rs index 5a362b0012..7548cb8ada 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words512.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words512.rs @@ -1,7 +1,8 @@ use crate::{ evm_circuit::util::{ - self, constraint_builder::ConstraintBuilder, from_bytes, pow_of_two_expr, split_u256, - split_u256_limb64, CachedRegion, Cell, + self, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + from_bytes, pow_of_two_expr, split_u256, split_u256_limb64, CachedRegion, Cell, }, util::Expr, }; @@ -50,7 +51,7 @@ impl MulAddWords512Gadget { /// The words argument is: a, b, d, e /// Addend is the optional c. pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, words: [&util::Word; 4], addend: Option<&util::Word>, ) -> Self { @@ -210,7 +211,7 @@ mod tests { } impl MathGadgetContainer for MulAddWords512GadgetContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_word_rlc(); let b = cb.query_word_rlc(); let d = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_word_u64.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_word_u64.rs index 60acbd250d..1c5ce03e1e 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_word_u64.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/mul_word_u64.rs @@ -1,7 +1,8 @@ use crate::{ evm_circuit::util::{ - self, constraint_builder::ConstraintBuilder, from_bytes, pow_of_two_expr, split_u256, - CachedRegion, + self, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + from_bytes, pow_of_two_expr, split_u256, CachedRegion, }, util::Expr, }; @@ -22,7 +23,7 @@ pub(crate) struct MulWordByU64Gadget { impl MulWordByU64Gadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, multiplicand: util::Word, multiplier: Expression, ) -> Self { @@ -106,7 +107,7 @@ mod tests { } impl MathGadgetContainer for MulWordByU64TestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_word_rlc(); let b = cb.query_cell(); let product = cb.query_word_rlc(); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/pair_select.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/pair_select.rs index c525bb438e..898c4c4801 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/pair_select.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/pair_select.rs @@ -1,5 +1,8 @@ use crate::{ - evm_circuit::util::{constraint_builder::ConstraintBuilder, CachedRegion, Cell}, + evm_circuit::util::{ + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + CachedRegion, Cell, + }, util::Expr, }; use eth_types::Field; @@ -22,7 +25,7 @@ pub struct PairSelectGadget { impl PairSelectGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, value: Expression, a: Expression, b: Expression, @@ -59,6 +62,8 @@ impl PairSelectGadget { #[cfg(test)] mod tests { + use crate::evm_circuit::util::constraint_builder::ConstrainBuilderCommon; + use super::{super::test_util::*, *}; use eth_types::*; use halo2_proofs::{halo2curves::bn256::Fr, plonk::Error}; @@ -75,7 +80,7 @@ mod tests { impl MathGadgetContainer for PairSelectionTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let v = cb.query_cell(); let a = cb.query_cell(); let b = cb.query_cell(); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/range_check.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/range_check.rs index 7e9ccf5282..989011c68a 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/range_check.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/range_check.rs @@ -1,5 +1,6 @@ use crate::evm_circuit::util::{ - constraint_builder::ConstraintBuilder, from_bytes, CachedRegion, Cell, + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + from_bytes, CachedRegion, Cell, }; use eth_types::Field; use halo2_proofs::{ @@ -15,7 +16,7 @@ pub struct RangeCheckGadget { } impl RangeCheckGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, value: Expression) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, value: Expression) -> Self { let parts = cb.query_bytes(); // Require that the reconstructed value from the parts equals the @@ -60,7 +61,7 @@ mod tests { impl MathGadgetContainer for RangeCheckTestContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let a = cb.query_cell(); let range_check_gadget = RangeCheckGadget::::construct(cb, a.expr()); RangeCheckTestContainer { diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs index d3932caccc..81dfe9c205 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs @@ -7,7 +7,10 @@ use halo2_proofs::{ use crate::evm_circuit::{ param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_U64, N_BYTES_WORD}, - util::{constraint_builder::ConstraintBuilder, CachedRegion, Cell, RandomLinearCombination}, + util::{ + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + CachedRegion, Cell, RandomLinearCombination, + }, }; use super::IsZeroGadget; @@ -26,7 +29,7 @@ pub struct RlpU64Gadget { impl RlpU64Gadget { /// Configure and construct a gadget for RLP-encoding of a U64 value. - fn construct(cb: &mut ConstraintBuilder) -> Self { + fn construct(cb: &mut EVMConstraintBuilder) -> Self { let value_rlc = cb.query_keccak_rlc(); let is_most_significant_byte = array_init::array_init(|_| cb.query_bool()); @@ -143,7 +146,7 @@ impl RlpU64Gadget { } /// RLC for the RLP-encoding of the U64 value. - fn rlp_rlc(&self, cb: &ConstraintBuilder) -> Expression { + fn rlp_rlc(&self, cb: &EVMConstraintBuilder) -> Expression { select::expr( and::expr([ self.is_lt_128.expr(), @@ -155,7 +158,7 @@ impl RlpU64Gadget { ) } - fn challenge_power_rlp_length(&self, cb: &ConstraintBuilder) -> Expression { + fn challenge_power_rlp_length(&self, cb: &EVMConstraintBuilder) -> Expression { cb.challenges().keccak_input() * select::expr( self.is_lt_128.expr(), @@ -164,7 +167,7 @@ impl RlpU64Gadget { ) } - fn challenge_power_n_bytes(&self, cb: &ConstraintBuilder) -> Expression { + fn challenge_power_n_bytes(&self, cb: &EVMConstraintBuilder) -> Expression { select::expr( self.most_significant_byte_is_zero.expr(), 1.expr(), @@ -196,7 +199,7 @@ pub struct ContractCreateGadget { impl ContractCreateGadget { /// Configure and construct the gadget. - pub(crate) fn construct(cb: &mut ConstraintBuilder) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder) -> Self { let caller_address = cb.query_keccak_rlc(); let nonce = RlpU64Gadget::construct(cb); let code_hash = array_init::array_init(|_| cb.query_byte()); @@ -254,7 +257,7 @@ impl ContractCreateGadget { } /// Code hash word RLC. - pub(crate) fn code_hash_word_rlc(&self, cb: &ConstraintBuilder) -> Expression { + pub(crate) fn code_hash_word_rlc(&self, cb: &EVMConstraintBuilder) -> Expression { cb.word_rlc::( self.code_hash .iter() @@ -266,7 +269,7 @@ impl ContractCreateGadget { } /// Code hash keccak RLC. - pub(crate) fn code_hash_keccak_rlc(&self, cb: &ConstraintBuilder) -> Expression { + pub(crate) fn code_hash_keccak_rlc(&self, cb: &EVMConstraintBuilder) -> Expression { cb.keccak_rlc::( self.code_hash .iter() @@ -308,7 +311,7 @@ impl ContractCreateGadget { } /// RLC for the input data. - pub(crate) fn input_rlc(&self, cb: &ConstraintBuilder) -> Expression { + pub(crate) fn input_rlc(&self, cb: &EVMConstraintBuilder) -> Expression { let challenges = cb.challenges().keccak_powers_of_randomness::<21>(); let challenge_power_20 = challenges[19].clone(); if IS_CREATE2 { @@ -344,7 +347,10 @@ mod test { use gadgets::util::{not, Expr}; use halo2_proofs::halo2curves::bn256::Fr; - use crate::evm_circuit::util::{constraint_builder::ConstraintBuilder, CachedRegion, Cell}; + use crate::evm_circuit::util::{ + constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, + CachedRegion, Cell, + }; #[derive(Clone)] struct ContractCreateGadgetContainer { @@ -357,7 +363,7 @@ mod test { impl MathGadgetContainer for ContractCreateGadgetContainer { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self { + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self { let create_gadget = ContractCreateGadget::construct(cb); let input_len_expected = cb.query_cell(); let create_input_rlc_expected = array_init::array_init(|_| cb.query_byte()); diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs index 169b879112..0b8e6339f5 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs @@ -8,7 +8,7 @@ use crate::{ step::{ExecutionState, Step}, table::{FixedTableTag, Table}, util::{ - constraint_builder::ConstraintBuilder, rlc, CachedRegion, CellType, Expr, + constraint_builder::EVMConstraintBuilder, rlc, CachedRegion, CellType, Expr, StoredExpression, LOOKUP_CONFIG, }, Advice, Column, Fixed, @@ -45,7 +45,7 @@ pub(crate) fn generate_power_of_randomness(randomness: F) -> Vec { } pub(crate) trait MathGadgetContainer: Clone { - fn configure_gadget_container(cb: &mut ConstraintBuilder) -> Self + fn configure_gadget_container(cb: &mut EVMConstraintBuilder) -> Self where Self: Sized; @@ -125,7 +125,7 @@ impl> Circuit for UnitTestMathGadgetBaseC let step_curr = Step::new(meta, advices, 0, false); let step_next = Step::new(meta, advices, MAX_STEP_HEIGHT, true); - let mut cb = ConstraintBuilder::new( + let mut cb = EVMConstraintBuilder::new( step_curr.clone(), step_next, &challenges_exprs, diff --git a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs index 00d6846687..87b6f52683 100644 --- a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs @@ -1,9 +1,9 @@ -use super::CachedRegion; +use super::{constraint_builder::ConstrainBuilderCommon, CachedRegion}; use crate::{ evm_circuit::{ param::{N_BYTES_GAS, N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, util::{ - constraint_builder::ConstraintBuilder, + constraint_builder::EVMConstraintBuilder, from_bytes, math_gadget::{ConstantDivisionGadget, IsZeroGadget, MinMaxGadget, RangeCheckGadget}, select, sum, Cell, CellType, MemoryAddress, @@ -71,7 +71,7 @@ pub(crate) struct MemoryAddressGadget { impl MemoryAddressGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, memory_offset: Cell, memory_length: MemoryAddress, ) -> Self { @@ -169,7 +169,7 @@ pub(crate) struct MemoryWordSizeGadget { } impl MemoryWordSizeGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, address: Expression) -> Self { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, address: Expression) -> Self { let memory_word_size = ConstantDivisionGadget::construct(cb, address + 31.expr(), 32); Self { memory_word_size } @@ -216,7 +216,10 @@ impl /// Output ranges: /// - `next_memory_word_size < 256**MAX_MEMORY_SIZE_IN_BYTES` /// - `gas_cost <= GAS_MEM*256**MAX_MEMORY_SIZE_IN_BYTES + 256**MAX_QUAD_COST_IN_BYTES` - pub(crate) fn construct(cb: &mut ConstraintBuilder, addresses: [Expression; N]) -> Self { + pub(crate) fn construct( + cb: &mut EVMConstraintBuilder, + addresses: [Expression; N], + ) -> Self { // Calculate the memory size of the memory access // `address_memory_word_size < 256**MAX_MEMORY_SIZE_IN_BYTES` let memory_word_sizes = @@ -353,7 +356,7 @@ impl MemoryCopierGasGadget { /// - `next_memory_size < 256**MAX_MEMORY_SIZE_IN_BYTES` /// - `gas_cost <= GAS_MEM*256**MAX_MEMORY_SIZE_IN_BYTES + 256**MAX_QUAD_COST_IN_BYTES` pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, num_bytes: Expression, memory_expansion_gas_cost: Expression, ) -> Self { @@ -414,7 +417,7 @@ impl BufferReaderGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut EVMConstraintBuilder, addr_start: Expression, addr_end: Expression, ) -> Self { diff --git a/zkevm-circuits/src/exp_circuit.rs b/zkevm-circuits/src/exp_circuit.rs index b050077455..2bd2c05aaa 100644 --- a/zkevm-circuits/src/exp_circuit.rs +++ b/zkevm-circuits/src/exp_circuit.rs @@ -25,6 +25,8 @@ use halo2_proofs::{ plonk::{ConstraintSystem, Error, Selector}, poly::Rotation, }; + +use crate::evm_circuit::util::constraint_builder::ConstrainBuilderCommon; use param::*; use std::{marker::PhantomData, ops::Add}; diff --git a/zkevm-circuits/src/keccak_circuit.rs b/zkevm-circuits/src/keccak_circuit.rs index 0fe0f2a6a2..8cbcb06e21 100644 --- a/zkevm-circuits/src/keccak_circuit.rs +++ b/zkevm-circuits/src/keccak_circuit.rs @@ -17,9 +17,20 @@ pub use dev::KeccakCircuit as TestKeccakCircuit; use std::marker::PhantomData; pub use KeccakCircuitConfig as KeccakConfig; -use self::{cell_manager::*, keccak_packed_multi::*, param::*, table::*, util::*}; +use self::{ + cell_manager::*, + keccak_packed_multi::{multi_keccak, KeccakRow}, + param::*, + table::*, + util::*, +}; use crate::{ - evm_circuit::util::constraint_builder::BaseConstraintBuilder, + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, + keccak_circuit::keccak_packed_multi::{ + decode, get_num_bits_per_absorb_lookup, get_num_bits_per_base_chi_lookup, + get_num_bits_per_rho_pi_lookup, get_num_bits_per_theta_c_lookup, get_num_rows_per_round, + split, split_uniform, transform, transform_to, Part, + }, table::{KeccakTable, LookupTable}, util::{Challenges, SubCircuit, SubCircuitConfig}, witness, diff --git a/zkevm-circuits/src/keccak_circuit/cell_manager.rs b/zkevm-circuits/src/keccak_circuit/cell_manager.rs index fe87a71ce3..c0c671bddb 100644 --- a/zkevm-circuits/src/keccak_circuit/cell_manager.rs +++ b/zkevm-circuits/src/keccak_circuit/cell_manager.rs @@ -1,4 +1,4 @@ -use crate::keccak_circuit::{util::extract_field, KeccakRegion}; +use crate::keccak_circuit::util::extract_field; use gadgets::util::Expr; use halo2_proofs::{ arithmetic::FieldExt, @@ -7,6 +7,8 @@ use halo2_proofs::{ poly::Rotation, }; +use super::keccak_packed_multi::KeccakRegion; + #[derive(Clone, Debug)] pub(crate) struct Cell { pub(crate) expression: Expression, diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index 6d9589f9c2..5f5175edb7 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -125,7 +125,7 @@ pub(crate) mod decode { pub(crate) mod split { use super::{decode, CellManager, KeccakRegion, Part, PartValue}; use crate::{ - evm_circuit::util::constraint_builder::BaseConstraintBuilder, + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, keccak_circuit::util::{pack, pack_part, unpack, WordParts}, util::Expr, }; @@ -188,7 +188,7 @@ pub(crate) mod split { pub(crate) mod split_uniform { use super::{decode, target_part_sizes, Cell, CellManager, KeccakRegion, Part, PartValue}; use crate::{ - evm_circuit::util::constraint_builder::BaseConstraintBuilder, + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, keccak_circuit::{ param::BIT_COUNT, util::{pack, pack_part, rotate, rotate_rev, unpack, WordParts}, diff --git a/zkevm-circuits/src/util/cell_manager.rs b/zkevm-circuits/src/util/cell_manager.rs new file mode 100644 index 0000000000..97a7ee493f --- /dev/null +++ b/zkevm-circuits/src/util/cell_manager.rs @@ -0,0 +1,8 @@ +trait CellManagerStrategy { + fn query_top_aligned_cell(&mut self, cell_type: CellType) -> Cell; + fn query_cell(&mut self, cell_type: CellType) -> Cell; + fn query_cells(&mut self, cell_type: CellType, count: usize) -> Vec>; + fn columns(&self) -> &[CellColumn]; + fn get_width(&self) -> usize; + fn get_height(&self) -> usize; +} From e687615108a9e12634d8334a2e15aef26240a27a Mon Sep 17 00:00:00 2001 From: Akase Cho Date: Thu, 27 Apr 2023 09:01:59 +0800 Subject: [PATCH 016/102] [feat] add memory reconstruction for precompile (#1372) ### Description Added memory reconstruction for call to precompile contracts. ### Issue Link No issue is associated with this pull request. ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - Added a new function `is_precompiled` to check if the address of the contract is a precompiled contract. - Added a new function `execute_precompiled` to execute a precompiled contract. - Added a new helper function `code_address` associated with `Call` struct to get the actual address of code execution. - Reconstruct memory for call to precompile address. ### Rationale The addition of support for call to precompiled contracts in bus-mapping allows no-memory exec trace. ### How Has This Been Tested? This PR only includes the memory reconstruction part. It has been test locally via `bus_mapping::evm::opcodes::callop::tests::test_precompiled_call`. --------- Co-authored-by: Zhang Zhuo --- Cargo.lock | 380 +++++++++++++-- bus-mapping/Cargo.toml | 2 + bus-mapping/src/circuit_input_builder/call.rs | 12 + bus-mapping/src/evm/opcodes/callop.rs | 449 +++++++++++++++++- bus-mapping/src/lib.rs | 1 + bus-mapping/src/precompile.rs | 23 + 6 files changed, 807 insertions(+), 60 deletions(-) create mode 100644 bus-mapping/src/precompile.rs diff --git a/Cargo.lock b/Cargo.lock index c68b4b3268..db1af7910f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,6 +161,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base58" version = "0.1.0" @@ -421,6 +427,7 @@ dependencies = [ "mock", "pretty_assertions", "rand", + "revm-precompile", "serde", "serde_json", "strum", @@ -654,7 +661,7 @@ dependencies = [ "digest 0.10.6", "getrandom", "hmac 0.12.1", - "k256", + "k256 0.11.6", "lazy_static", "serde", "sha2 0.10.6", @@ -695,7 +702,7 @@ dependencies = [ "serde", "serde_derive", "sha2 0.10.6", - "sha3 0.10.6", + "sha3 0.10.7", "thiserror", ] @@ -724,9 +731,9 @@ checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" [[package]] name = "const-oid" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "constant_time_eq" @@ -734,6 +741,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "convert_case" version = "0.5.0" @@ -908,6 +921,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7" +dependencies = [ + "generic-array 0.14.6", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -1093,6 +1118,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e58dffcdcc8ee7b22f0c1f71a69243d7c2d9ad87b5a14361f2424a1565c219" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "derive_builder" version = "0.9.0" @@ -1118,6 +1153,19 @@ dependencies = [ "syn", ] +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn", +] + [[package]] name = "diff" version = "0.1.13" @@ -1158,6 +1206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer 0.10.3", + "const-oid", "crypto-common", "subtle", ] @@ -1215,7 +1264,7 @@ name = "ecc" version = "0.1.0" source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" dependencies = [ - "group", + "group 0.12.1", "integer", "num-bigint", "num-integer", @@ -1230,7 +1279,7 @@ version = "0.1.0" source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" dependencies = [ "ecc", - "group", + "group 0.12.1", "num-bigint", "num-integer", "num-traits", @@ -1244,10 +1293,23 @@ version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] + +[[package]] +name = "ecdsa" +version = "0.16.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd" +dependencies = [ + "der 0.7.5", + "digest 0.10.6", + "elliptic-curve 0.13.4", + "rfc6979 0.4.0", + "signature 2.1.0", ] [[package]] @@ -1262,16 +1324,34 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ - "base16ct", - "crypto-bigint", - "der", + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", "digest 0.10.6", - "ff", + "ff 0.12.1", "generic-array 0.14.6", - "group", + "group 0.12.1", "pkcs8", "rand_core", - "sec1", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.1", + "digest 0.10.6", + "ff 0.13.0", + "generic-array 0.14.6", + "group 0.13.0", + "rand_core", + "sec1 0.7.1", "subtle", "zeroize", ] @@ -1300,6 +1380,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enumn" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1940ea32e14d489b401074558be4567f35ca9507c4628b4b3fd6fe6eb2ca7b88" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" version = "0.9.3" @@ -1351,7 +1442,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.6", - "sha3 0.10.6", + "sha3 0.10.7", "thiserror", "uuid", ] @@ -1373,7 +1464,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "sha3 0.10.6", + "sha3 0.10.7", "strum", "strum_macros", "subtle", @@ -1392,7 +1483,7 @@ dependencies = [ "regex", "serde", "serde_json", - "sha3 0.10.6", + "sha3 0.10.7", "thiserror", "uint", ] @@ -1404,7 +1495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" dependencies = [ "crunchy", - "fixed-hash", + "fixed-hash 0.7.0", "impl-rlp", "impl-serde", "tiny-keccak", @@ -1417,10 +1508,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" dependencies = [ "ethbloom", - "fixed-hash", + "fixed-hash 0.7.0", "impl-rlp", "impl-serde", - "primitive-types", + "primitive-types 0.11.1", "uint", ] @@ -1478,13 +1569,13 @@ dependencies = [ "arrayvec", "bytes", "chrono", - "convert_case", - "elliptic-curve", + "convert_case 0.5.0", + "elliptic-curve 0.12.3", "ethabi", "fastrlp", "generic-array 0.14.6", "hex", - "k256", + "k256 0.11.6", "proc-macro2", "rand", "rlp", @@ -1587,7 +1678,7 @@ dependencies = [ "async-trait", "coins-bip32", "coins-bip39", - "elliptic-curve", + "elliptic-curve 0.12.3", "eth-keystore", "ethers-core", "hex", @@ -1679,6 +1770,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "fixed-hash" version = "0.7.0" @@ -1691,6 +1792,16 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1949,6 +2060,7 @@ checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -2004,7 +2116,18 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "ff", + "ff 0.12.1", + "rand_core", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", "rand_core", "subtle", ] @@ -2041,8 +2164,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e925780549adee8364c7f2b685c753f6f3df23bde520c67416e93bf615933760" dependencies = [ "blake2b_simd", - "ff", - "group", + "ff 0.12.1", + "group 0.12.1", "pasta_curves", "plotters", "rand_core", @@ -2056,8 +2179,8 @@ version = "0.2.0" source = "git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02#0a8646b78286a13d320759b1c585262d6536dce4" dependencies = [ "blake2b_simd", - "ff", - "group", + "ff 0.12.1", + "group 0.12.1", "halo2curves 0.3.1", "rand_core", "rayon", @@ -2070,8 +2193,8 @@ name = "halo2curves" version = "0.2.1" source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.0#83c72d49762343ffc9576ca11a2aa615efe1029b" dependencies = [ - "ff", - "group", + "ff 0.12.1", + "group 0.12.1", "lazy_static", "num-bigint", "num-traits", @@ -2087,8 +2210,8 @@ name = "halo2curves" version = "0.3.1" source = "git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1#9b67e19bca30a35208b0c1b41c1723771e2c9f49" dependencies = [ - "ff", - "group", + "ff 0.12.1", + "group 0.12.1", "lazy_static", "num-bigint", "num-traits", @@ -2104,7 +2227,7 @@ name = "halo2wrong" version = "0.1.0" source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" dependencies = [ - "group", + "group 0.12.1", "halo2_proofs 0.2.0", "num-bigint", "num-integer", @@ -2188,6 +2311,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "hmac" version = "0.8.1" @@ -2424,7 +2553,7 @@ name = "integer" version = "0.1.0" source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" dependencies = [ - "group", + "group 0.12.1", "maingate", "num-bigint", "num-integer", @@ -2529,9 +2658,21 @@ checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" dependencies = [ "cfg-if", "ecdsa 0.14.8", - "elliptic-curve", + "elliptic-curve 0.12.3", + "sha2 0.10.6", + "sha3 0.10.7", +] + +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa 0.16.6", + "elliptic-curve 0.13.4", "sha2 0.10.6", - "sha3 0.10.6", ] [[package]] @@ -2597,6 +2738,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -2707,7 +2851,7 @@ name = "maingate" version = "0.1.0" source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" dependencies = [ - "group", + "group 0.12.1", "halo2wrong", "num-bigint", "num-integer", @@ -3025,8 +3169,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cc65faf8e7313b4b1fbaa9f7ca917a0eed499a9663be71477f87993604341d8" dependencies = [ "blake2b_simd", - "ff", - "group", + "ff 0.12.1", + "group 0.12.1", "lazy_static", "rand", "static_assertions", @@ -3243,7 +3387,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ - "der", + "der 0.6.1", "spki", ] @@ -3316,7 +3460,7 @@ name = "poseidon" version = "0.2.0" source = "git+https://github.com/privacy-scaling-explorations/poseidon.git?tag=v2022_10_22#5d29df01a95e3df6334080d28e983407f56b5da3" dependencies = [ - "group", + "group 0.12.1", "halo2curves 0.2.1", "subtle", ] @@ -3365,13 +3509,23 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" dependencies = [ - "fixed-hash", + "fixed-hash 0.7.0", "impl-codec", "impl-rlp", "impl-serde", "uint", ] +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash 0.8.0", + "uint", +] + [[package]] name = "proc-macro-crate" version = "0.1.5" @@ -3623,17 +3777,65 @@ dependencies = [ "winreg", ] +[[package]] +name = "revm-precompile" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a3eabf08ea9e4063f5531b8735e29344d9d6eaebaa314c58253f6c17fcdf2d" +dependencies = [ + "k256 0.13.1", + "num", + "once_cell", + "revm-primitives", + "ripemd", + "secp256k1", + "sha2 0.10.6", + "sha3 0.10.7", + "substrate-bn", +] + +[[package]] +name = "revm-primitives" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180427e1169b860ab63eaa5bcff158010073646abf3312aed11a1d7aa1aa8291" +dependencies = [ + "auto_impl", + "bitvec 1.0.1", + "bytes", + "derive_more", + "enumn", + "fixed-hash 0.8.0", + "hashbrown 0.13.2", + "hex", + "hex-literal", + "primitive-types 0.12.1", + "rlp", + "ruint", + "sha3 0.10.7", +] + [[package]] name = "rfc6979" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ - "crypto-bigint", + "crypto-bigint 0.4.9", "hmac 0.12.1", "zeroize", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -3704,6 +3906,26 @@ dependencies = [ "syn", ] +[[package]] +name = "ruint" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d470e29e933dac4101180fd6574971892315c414cf2961a192729089687cc9b" +dependencies = [ + "derive_more", + "primitive-types 0.11.1", + "rlp", + "ruint-macro", + "rustc_version 0.4.0", + "thiserror", +] + +[[package]] +name = "ruint-macro" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62cc5760263ea229d367e7dff3c0cbf09e4797a125bd87059a6c095804f3b2d1" + [[package]] name = "rust_decimal" version = "1.28.1" @@ -3858,14 +4080,45 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "base16ct", - "der", + "base16ct 0.1.1", + "der 0.6.1", "generic-array 0.14.6", "pkcs8", "subtle", "zeroize", ] +[[package]] +name = "sec1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.5", + "generic-array 0.14.6", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + [[package]] name = "semver" version = "0.11.0" @@ -4057,9 +4310,9 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +checksum = "54c2bb1a323307527314a36bfb73f24febb08ce2b8a554bf4ffd6f51ad15198c" dependencies = [ "digest 0.10.6", "keccak", @@ -4075,6 +4328,16 @@ dependencies = [ "rand_core", ] +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.6", + "rand_core", +] + [[package]] name = "siphasher" version = "0.3.10" @@ -4150,7 +4413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", - "der", + "der 0.6.1", ] [[package]] @@ -4206,6 +4469,19 @@ dependencies = [ "syn", ] +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand", + "rustc-hex", +] + [[package]] name = "subtle" version = "2.4.1" @@ -5029,7 +5305,7 @@ dependencies = [ "rand_xorshift", "serde", "serde_json", - "sha3 0.10.6", + "sha3 0.10.7", "snark-verifier", "strum", "strum_macros", diff --git a/bus-mapping/Cargo.toml b/bus-mapping/Cargo.toml index 65b0b411da..a60f1daab9 100644 --- a/bus-mapping/Cargo.toml +++ b/bus-mapping/Cargo.toml @@ -23,6 +23,8 @@ serde_json = "1.0.66" strum = "0.24" strum_macros = "0.24" +revm-precompile = "2.0.2" + [dev-dependencies] hex = "0.4.3" pretty_assertions = "1.0.0" diff --git a/bus-mapping/src/circuit_input_builder/call.rs b/bus-mapping/src/circuit_input_builder/call.rs index 8f4098134c..76fcc43280 100644 --- a/bus-mapping/src/circuit_input_builder/call.rs +++ b/bus-mapping/src/circuit_input_builder/call.rs @@ -108,6 +108,18 @@ impl Call { pub fn is_delegatecall(&self) -> bool { matches!(self.kind, CallKind::DelegateCall) } + + /// Get the code address if possible + pub fn code_address(&self) -> Option
{ + match self.kind { + CallKind::Call | CallKind::StaticCall => Some(self.address), + CallKind::CallCode | CallKind::DelegateCall => match self.code_source { + CodeSource::Address(address) => Some(address), + _ => None, + }, + CallKind::Create | CallKind::Create2 => None, + } + } } /// Context of a [`Call`]. diff --git a/bus-mapping/src/evm/opcodes/callop.rs b/bus-mapping/src/evm/opcodes/callop.rs index d080e96fae..0310ea1ac2 100644 --- a/bus-mapping/src/evm/opcodes/callop.rs +++ b/bus-mapping/src/evm/opcodes/callop.rs @@ -2,6 +2,7 @@ use super::Opcode; use crate::{ circuit_input_builder::{CallKind, CircuitInputStateRef, CodeSource, ExecStep}, operation::{AccountField, CallContextField, TxAccessListAccountOp}, + precompile::{execute_precompiled, is_precompiled}, state_db::CodeDB, Error, }; @@ -10,8 +11,9 @@ use eth_types::{ gas_utils::{eip150_gas, memory_expansion_gas_cost}, GasCost, }, - evm_unimplemented, GethExecStep, ToWord, Word, + GethExecStep, ToWord, Word, }; +use std::cmp::min; /// Placeholder structure used to implement [`Opcode`] trait over it /// corresponding to the `OpcodeId::CALL`, `OpcodeId::CALLCODE`, @@ -162,6 +164,10 @@ impl Opcode for CallOpcode { caller_balance, ); + let code_address = call.code_address(); + let is_precompile = code_address + .map(|ref addr| is_precompiled(addr)) + .unwrap_or(false); // TODO: What about transfer for CALLCODE? // Transfer value only for CALL opcode, insufficient_balance = false. if call.kind == CallKind::Call && !insufficient_balance { @@ -169,7 +175,7 @@ impl Opcode for CallOpcode { &mut exec_step, call.caller_address, call.address, - callee_exists, + callee_exists || is_precompile, false, call.value, )?; @@ -210,14 +216,57 @@ impl Opcode for CallOpcode { // There are 4 branches from here. // add failure case for insufficient balance or error depth in the future. - match ( - insufficient_balance, - state.is_precompiled(&call.address), - is_empty_code_hash, - ) { + match (insufficient_balance, is_precompile, is_empty_code_hash) { // 1. Call to precompiled. (false, true, _) => { - evm_unimplemented!("Call to precompiled is left unimplemented"); + assert!(call.is_success, "call to precompile should not fail"); + let caller_ctx = state.caller_ctx_mut()?; + let code_address = code_address.unwrap(); + let (result, contract_gas_cost) = execute_precompiled( + &code_address, + if args_length != 0 { + &caller_ctx.memory.0[args_offset..args_offset + args_length] + } else { + &[] + }, + callee_gas_left, + ); + log::trace!( + "precompile return data len {} gas {}", + result.len(), + contract_gas_cost + ); + caller_ctx.return_data = result.clone(); + let length = min(result.len(), ret_length); + if length != 0 { + caller_ctx.memory.extend_at_least(ret_offset + length); + } + caller_ctx.memory.0[ret_offset..ret_offset + length] + .copy_from_slice(&result[..length]); + for (field, value) in [ + (CallContextField::LastCalleeId, call.call_id.into()), + (CallContextField::LastCalleeReturnDataOffset, 0.into()), + ( + CallContextField::LastCalleeReturnDataLength, + result.len().into(), + ), + ] { + state.call_context_write(&mut exec_step, current_call.call_id, field, value); + } + + log::warn!("missing circuit part of precompile"); + state.handle_return(&mut exec_step, geth_steps, false)?; + + let real_cost = geth_steps[0].gas.0 - geth_steps[1].gas.0; + if real_cost != exec_step.gas_cost.0 { + log::warn!( + "precompile gas fixed from {} to {}, step {:?}", + exec_step.gas_cost.0, + real_cost, + geth_steps[0] + ); + } + exec_step.gas_cost = GasCost(real_cost); Ok(vec![exec_step]) } // 2. Call to account with empty code. @@ -312,3 +361,387 @@ impl Opcode for CallOpcode { } } } + +#[cfg(test)] +mod tests { + use crate::{circuit_input_builder::CircuitsParams, mock::BlockData}; + use eth_types::{bytecode, evm_types::OpcodeId, geth_types::GethData, word, Bytecode, Word}; + use mock::{ + test_ctx::{ + helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, + LoggerConfig, + }, + TestContext, + }; + + // move this to circuit after circuit part is complete + #[test] + fn test_precompiled_call() { + struct PrecompileCall { + name: &'static str, + setup_code: Bytecode, + ret_size: Word, + ret_offset: Word, + call_data_offset: Word, + call_data_length: Word, + address: Word, + value: Word, + gas: Word, + stack_value: Vec<(Word, Word)>, + max_rws: usize, + } + + impl Default for PrecompileCall { + fn default() -> Self { + PrecompileCall { + name: "precompiled call", + setup_code: Bytecode::default(), + ret_size: Word::from(0), + ret_offset: Word::from(0), + call_data_offset: Word::from(0), + call_data_length: Word::from(0), + address: Word::from(0), + value: Word::from(0), + gas: Word::from(0xFFFFFFF), + stack_value: vec![], + max_rws: 500, + } + } + } + + impl PrecompileCall { + fn with_call_op(&self, call_op: OpcodeId) -> Bytecode { + assert!( + call_op.is_call(), + "invalid setup, {:?} is not a call op", + call_op + ); + let mut code = self.setup_code.clone(); + code.push(32, self.ret_size) + .push(32, self.ret_offset) + .push(32, self.call_data_length) + .push(32, self.call_data_offset); + if call_op == OpcodeId::CALL || call_op == OpcodeId::CALLCODE { + code.push(32, self.value); + } + code.push(32, self.address) + .push(32, self.gas) + .write_op(call_op) + .write_op(OpcodeId::POP); + for (offset, _) in self.stack_value.iter().rev() { + code.push(32, *offset).write_op(OpcodeId::MLOAD); + } + + code + } + } + + let test_vector = [ + PrecompileCall { + name: "ecRecover", + setup_code: bytecode! { + PUSH32(word!("0x456e9aea5e197a1f1af7a3e85a3212fa4049a3ba34c2289b4c860fc0b0c64ef3")) // hash + PUSH1(0x0) + MSTORE + PUSH1(28) // v + PUSH1(0x20) + MSTORE + PUSH32(word!("0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608")) // r + PUSH1(0x40) + MSTORE + PUSH32(word!("0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada")) // s + PUSH1(0x60) + MSTORE + }, + ret_size: Word::from(0x20), + ret_offset: Word::from(0x80), + call_data_length: Word::from(0x80), + address: Word::from(0x1), + stack_value: vec![( + Word::from(0x80), + word!("7156526fbd7a3c72969b54f64e42c10fbb768c8a"), + )], + ..Default::default() + }, + PrecompileCall { + name: "SHA2-256", + setup_code: bytecode! { + PUSH1(0xFF) // data + PUSH1(0) + MSTORE + }, + ret_size: Word::from(0x20), + ret_offset: Word::from(0x20), + call_data_length: Word::from(0x1), + call_data_offset: Word::from(0x1F), + address: Word::from(0x2), + stack_value: vec![( + Word::from(0x20), + word!("a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89"), + )], + ..Default::default() + }, + PrecompileCall { + name: "RIPEMD-160", + setup_code: bytecode! { + PUSH1(0xFF) // data + PUSH1(0) + MSTORE + }, + ret_size: Word::from(0x20), + ret_offset: Word::from(0x20), + call_data_length: Word::from(0x1), + call_data_offset: Word::from(0x1F), + address: Word::from(0x3), + stack_value: vec![( + Word::from(0x20), + word!("2c0c45d3ecab80fe060e5f1d7057cd2f8de5e557"), + )], + ..Default::default() + }, + PrecompileCall { + name: "identity", + setup_code: bytecode! { + PUSH16(word!("0123456789ABCDEF0123456789ABCDEF")) + PUSH1(0x00) + MSTORE + }, + ret_size: Word::from(0x20), + ret_offset: Word::from(0x20), + call_data_length: Word::from(0x20), + address: Word::from(0x4), + stack_value: vec![(Word::from(0x20), word!("0123456789ABCDEF0123456789ABCDEF"))], + ..Default::default() + }, + PrecompileCall { + name: "modexp", + setup_code: bytecode! { + PUSH1(1) // Bsize + PUSH1(0) + MSTORE + PUSH1(1) // Esize + PUSH1(0x20) + MSTORE + PUSH1(1) // Msize + PUSH1(0x40) + MSTORE + PUSH32(word!("0x08090A0000000000000000000000000000000000000000000000000000000000")) // B, E and M + PUSH1(0x60) + MSTORE + }, + ret_size: Word::from(0x01), + ret_offset: Word::from(0x9F), + call_data_length: Word::from(0x63), + address: Word::from(0x5), + stack_value: vec![(Word::from(0x80), Word::from(8))], + ..Default::default() + }, + PrecompileCall { + name: "ecAdd", + setup_code: bytecode! { + PUSH1(1) // x1 + PUSH1(0) + MSTORE + PUSH1(2) // y1 + PUSH1(0x20) + MSTORE + PUSH1(1) // x2 + PUSH1(0x40) + MSTORE + PUSH1(2) // y2 + PUSH1(0x60) + MSTORE + }, + ret_size: Word::from(0x40), + ret_offset: Word::from(0x80), + call_data_length: Word::from(0x80), + address: Word::from(0x6), + stack_value: vec![ + ( + Word::from(0x80), + word!("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd3"), + ), + ( + Word::from(0xA0), + word!("15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4"), + ), + ], + ..Default::default() + }, + PrecompileCall { + name: "ecMul", + setup_code: bytecode! { + PUSH1(1) // x1 + PUSH1(0) + MSTORE + PUSH1(2) // y1 + PUSH1(0x20) + MSTORE + PUSH1(2) // s + PUSH1(0x40) + MSTORE + }, + ret_size: Word::from(0x40), + ret_offset: Word::from(0x60), + call_data_length: Word::from(0x60), + address: Word::from(0x7), + stack_value: vec![ + ( + Word::from(0x60), + word!("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd3"), + ), + ( + Word::from(0x80), + word!("15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4"), + ), + ], + ..Default::default() + }, + PrecompileCall { + name: "ecPairing", + setup_code: bytecode! { + PUSH32(word!("0x23a8eb0b0996252cb548a4487da97b02422ebc0e834613f954de6c7e0afdc1fc")) + PUSH32(word!("0x2a23af9a5ce2ba2796c1f4e453a370eb0af8c212d9dc9acd8fc02c2e907baea2")) + PUSH32(word!("0x091058a3141822985733cbdddfed0fd8d6c104e9e9eff40bf5abfef9ab163bc7")) + PUSH32(word!("0x1971ff0471b09fa93caaf13cbf443c1aede09cc4328f5a62aad45f40ec133eb4")) + PUSH32(word!("0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45")) + PUSH32(word!("0x0000000000000000000000000000000000000000000000000000000000000001")) + PUSH32(word!("0x2fe02e47887507adf0ff1743cbac6ba291e66f59be6bd763950bb16041a0a85e")) + PUSH32(word!("0x2bd368e28381e8eccb5fa81fc26cf3f048eea9abfdd85d7ed3ab3698d63e4f90")) + PUSH32(word!("0x22606845ff186793914e03e21df544c34ffe2f2f3504de8a79d9159eca2d98d9")) + PUSH32(word!("0x1fb19bb476f6b9e44e2a32234da8212f61cd63919354bc06aef31e3cfaff3ebc")) + PUSH32(word!("0x2c0f001f52110ccfe69108924926e45f0b0c868df0e7bde1fe16d3242dc715f6")) + PUSH32(word!("0x2cf44499d5d27bb186308b7af7af02ac5bc9eeb6a3d147c186b21fb1b76e18da")) + + PUSH1(12) + PUSH2(0x200) + MSTORE + + JUMPDEST + + PUSH2(0x200) + MLOAD + PUSH1(12) + SUB + PUSH1(0x20) + MUL + MSTORE + PUSH1(1) + PUSH2(0x200) + MLOAD + SUB + DUP1 + PUSH2(0x200) + MSTORE + PUSH2(0x192) + JUMPI + }, + ret_size: Word::from(0x20), + call_data_length: Word::from(0x180), + address: Word::from(0x8), + stack_value: vec![(Word::from(0x0), Word::from(1))], + max_rws: 3000, + ..Default::default() + }, + PrecompileCall { + name: "blake2f", + setup_code: bytecode! { + PUSH32(word!("0000000003000000000000000000000000000000010000000000000000000000")) + PUSH32(word!("0000000000000000000000000000000000000000000000000000000000000000")) + PUSH32(word!("0000000000000000000000000000000000000000000000000000000000000000")) + PUSH32(word!("0000000000000000000000000000000000000000000000000000000000000000")) + PUSH32(word!("19cde05b61626300000000000000000000000000000000000000000000000000")) + PUSH32(word!("3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e13")) + PUSH32(word!("0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f")) + + PUSH1(7) + PUSH2(0x160) + MSTORE + + JUMPDEST + + PUSH2(0x160) + MLOAD + PUSH1(7) + SUB + PUSH1(0x20) + MUL + MSTORE + PUSH1(1) + PUSH2(0x160) + MLOAD + SUB + DUP1 + PUSH2(0x160) + MSTORE + PUSH2(0xed) + JUMPI + }, + ret_size: Word::from(0x40), + ret_offset: Word::from(0x0), + call_data_length: Word::from(0xd5), + address: Word::from(0x9), + stack_value: vec![ + ( + Word::from(0x20), + word!("d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b"), + ), + ( + Word::from(0x0), + word!("8c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5"), + ), + ], + max_rws: 1500, + ..Default::default() + }, + ]; + + let call_ops = [ + OpcodeId::CALL, + OpcodeId::CALLCODE, + OpcodeId::DELEGATECALL, + OpcodeId::STATICCALL, + ]; + + for (test_call, call_op) in itertools::iproduct!(test_vector.iter(), call_ops.iter()) { + let code = test_call.with_call_op(*call_op); + let block: GethData = TestContext::<2, 1>::new_with_logger_config( + None, + account_0_code_account_1_no_code(code), + tx_from_1_to_0, + |block, _tx| block.number(0xcafeu64), + LoggerConfig { + enable_memory: true, + ..Default::default() + }, + ) + .unwrap() + .into(); + + let mut builder = BlockData::new_from_geth_data_with_params( + block.clone(), + CircuitsParams { + max_rws: test_call.max_rws, + ..Default::default() + }, + ) + .new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + + let step = block.geth_traces[0] + .struct_logs + .last() + .expect("at least one step"); + log::debug!("{:?}", step.stack); + for (offset, (_, stack_value)) in test_call.stack_value.iter().enumerate() { + assert_eq!( + *stack_value, + step.stack.nth_last(offset).expect("stack value not found"), + "stack output mismatch" + ); + } + } + } +} diff --git a/bus-mapping/src/lib.rs b/bus-mapping/src/lib.rs index ceef2e9fc7..131cf5ebe8 100644 --- a/bus-mapping/src/lib.rs +++ b/bus-mapping/src/lib.rs @@ -234,6 +234,7 @@ pub mod exec_trace; pub(crate) mod geth_errors; pub mod mock; pub mod operation; +pub mod precompile; pub mod rpc; pub mod state_db; pub use error::Error; diff --git a/bus-mapping/src/precompile.rs b/bus-mapping/src/precompile.rs new file mode 100644 index 0000000000..f082224e5d --- /dev/null +++ b/bus-mapping/src/precompile.rs @@ -0,0 +1,23 @@ +//! precompile helpers + +use eth_types::Address; +use revm_precompile::{Precompile, Precompiles}; + +/// Check if address is a precompiled or not. +pub fn is_precompiled(address: &Address) -> bool { + Precompiles::berlin() + .get(address.as_fixed_bytes()) + .is_some() +} + +pub(crate) fn execute_precompiled(address: &Address, input: &[u8], gas: u64) -> (Vec, u64) { + let Some(Precompile::Standard(precompile_fn)) = Precompiles::berlin() + .get(address.as_fixed_bytes()) else { + panic!("calling non-exist precompiled contract address") + }; + + match precompile_fn(input, gas) { + Ok((gas_cost, return_value)) => (return_value, gas_cost), + Err(_) => (vec![], gas), + } +} From ab6a91a34973a7b392caa8a188c01ee348aab6b9 Mon Sep 17 00:00:00 2001 From: Han Date: Thu, 27 Apr 2023 12:00:17 +0800 Subject: [PATCH 017/102] Add `SubCircuit::unusable_rows` and tests for each `SubCircuit` (#1282) ### Description To remove magic numbers for blinding factors, this PR adds an associated function `unusable_rows` for `SubCircuit` to returns their `unusable_rows`, which should be `meta.blinding_factors() + 1`. Tests are also added to make sure the returned values are correct. Note that currently `KeccakCircuit` could be configured by environment variable `KECCAK_ROWS` to decide how many rows a round would take, which affect the different rotation queried, and it's unfortunately not a easy way to compute how many different rotations are used, so this PR hardcodes the unusable rows from `KECCAK_ROWS = 1` to `20` for easy lookup. ### Issue Link https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/949 ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - [_item_] ### Rationale [_design decisions and extended information_] ### How Has This Been Tested? [_explanation_] --------- Co-authored-by: David Nevado Co-authored-by: "adria0.eth" <5526331+adria0@users.noreply.github.com> Co-authored-by: Eduard S --- circuit-benchmarks/src/bytecode_circuit.rs | 13 ++++++---- circuit-benchmarks/src/packed_multi_keccak.rs | 7 +++-- .../src/bytecode_circuit/circuit.rs | 15 +++++------ zkevm-circuits/src/bytecode_circuit/test.rs | 10 ++++++- zkevm-circuits/src/copy_circuit.rs | 6 +++++ zkevm-circuits/src/copy_circuit/test.rs | 9 +++++++ zkevm-circuits/src/evm_circuit.rs | 16 ++++++++++++ zkevm-circuits/src/exp_circuit.rs | 23 ++++++++++++++++ zkevm-circuits/src/exp_circuit/test.rs | 9 +++++++ zkevm-circuits/src/keccak_circuit.rs | 6 ++++- .../src/keccak_circuit/keccak_packed_multi.rs | 10 ++++++- zkevm-circuits/src/keccak_circuit/param.rs | 1 + zkevm-circuits/src/keccak_circuit/test.rs | 16 ++++++++++++ zkevm-circuits/src/keccak_circuit/util.rs | 4 +-- zkevm-circuits/src/pi_circuit.rs | 10 +++++++ zkevm-circuits/src/pi_circuit/dev.rs | 4 +++ zkevm-circuits/src/pi_circuit/test.rs | 11 ++++++++ zkevm-circuits/src/state_circuit.rs | 6 +++++ zkevm-circuits/src/state_circuit/test.rs | 10 ++++++- zkevm-circuits/src/super_circuit.rs | 17 ++++++++++-- zkevm-circuits/src/tx_circuit.rs | 6 +++++ zkevm-circuits/src/tx_circuit/test.rs | 14 +++++++--- zkevm-circuits/src/util.rs | 26 ++++++++++++++++++- zkevm-circuits/src/witness/block.rs | 6 ++--- 24 files changed, 224 insertions(+), 31 deletions(-) diff --git a/circuit-benchmarks/src/bytecode_circuit.rs b/circuit-benchmarks/src/bytecode_circuit.rs index 16c055410e..42ca583f35 100644 --- a/circuit-benchmarks/src/bytecode_circuit.rs +++ b/circuit-benchmarks/src/bytecode_circuit.rs @@ -23,9 +23,13 @@ mod tests { use rand::SeedableRng; use rand_xorshift::XorShiftRng; use std::env::var; - use zkevm_circuits::bytecode_circuit::bytecode_unroller::{unroll, UnrolledBytecode}; - - use zkevm_circuits::bytecode_circuit::TestBytecodeCircuit; + use zkevm_circuits::{ + bytecode_circuit::{ + bytecode_unroller::{unroll, UnrolledBytecode}, + TestBytecodeCircuit, + }, + util::SubCircuit, + }; #[cfg_attr(not(feature = "benches"), ignore)] #[test] @@ -45,8 +49,7 @@ mod tests { const MAX_BYTECODE_LEN: usize = 24576; let num_rows = 1 << degree; - const NUM_BLINDING_ROWS: usize = 7 - 1; - let max_bytecode_row_num = num_rows - NUM_BLINDING_ROWS; + let max_bytecode_row_num = num_rows - TestBytecodeCircuit::::unusable_rows(); let bytecode_len = std::cmp::min(MAX_BYTECODE_LEN, max_bytecode_row_num); let bytecodes_num: usize = max_bytecode_row_num / bytecode_len; diff --git a/circuit-benchmarks/src/packed_multi_keccak.rs b/circuit-benchmarks/src/packed_multi_keccak.rs index e9268b98a2..2810fbd984 100644 --- a/circuit-benchmarks/src/packed_multi_keccak.rs +++ b/circuit-benchmarks/src/packed_multi_keccak.rs @@ -21,7 +21,7 @@ mod tests { use rand::SeedableRng; use rand_xorshift::XorShiftRng; use std::env::var; - use zkevm_circuits::keccak_circuit::TestKeccakCircuit; + use zkevm_circuits::{keccak_circuit::TestKeccakCircuit, util::SubCircuit}; #[cfg_attr(not(feature = "benches"), ignore)] #[test] @@ -41,7 +41,10 @@ mod tests { let inputs = vec![(0u8..135).collect::>(); 3]; // Create the circuit. Leave last dozens of rows for blinding. - let circuit = TestKeccakCircuit::new(2usize.pow(degree) - 64, inputs); + let circuit = TestKeccakCircuit::new( + 2usize.pow(degree) - TestKeccakCircuit::::unusable_rows(), + inputs, + ); // Initialize the polynomial commitment parameters let mut rng = XorShiftRng::from_seed([ diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index b0235abaaa..8b6c19c7d0 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -879,15 +879,14 @@ impl BytecodeCircuit { impl SubCircuit for BytecodeCircuit { type Config = BytecodeCircuitConfig; + fn unusable_rows() -> usize { + // No column queried at more than 3 distinct rotations, so returns 6 as + // minimum unusable rows. + 6 + } + fn new_from_block(block: &witness::Block) -> Self { - // TODO: Find a nicer way to add the extra `128`. Is this to account for - // unusable rows? Then it could be calculated like this: - // fn unusable_rows>() -> usize { - // let mut cs = ConstraintSystem::default(); - // C::configure(&mut cs); - // cs.blinding_factors() - // } - let bytecode_size = block.circuits_params.max_bytecode + 128; + let bytecode_size = block.circuits_params.max_bytecode; Self::new_from_block_sized(block, bytecode_size) } diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 6d27db90a4..66555a15db 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -2,13 +2,21 @@ use crate::{ bytecode_circuit::{bytecode_unroller::*, circuit::BytecodeCircuit}, table::BytecodeFieldTag, - util::{is_push, keccak, Challenges, SubCircuit}, + util::{is_push, keccak, unusable_rows, Challenges, SubCircuit}, }; use bus_mapping::evm::OpcodeId; use eth_types::{Bytecode, Field, Word}; use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use log::error; +#[test] +fn bytecode_circuit_unusable_rows() { + assert_eq!( + BytecodeCircuit::::unusable_rows(), + unusable_rows::>(), + ) +} + impl BytecodeCircuit { /// Verify that the selected bytecode fulfills the circuit pub fn verify_raw(k: u32, bytecodes: Vec>) { diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index c0fa935714..b746a61460 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -731,6 +731,12 @@ impl CopyCircuit { impl SubCircuit for CopyCircuit { type Config = CopyCircuitConfig; + fn unusable_rows() -> usize { + // No column queried at more than 3 distinct rotations, so returns 6 as + // minimum unusable rows. + 6 + } + fn new_from_block(block: &witness::Block) -> Self { Self::new_with_external_data( block.copy_events.clone(), diff --git a/zkevm-circuits/src/copy_circuit/test.rs b/zkevm-circuits/src/copy_circuit/test.rs index 4fba9ce756..81d0183ee3 100644 --- a/zkevm-circuits/src/copy_circuit/test.rs +++ b/zkevm-circuits/src/copy_circuit/test.rs @@ -3,6 +3,7 @@ use crate::{ copy_circuit::*, evm_circuit::{test::rand_bytes, witness::block_convert}, + util::unusable_rows, witness::Block, }; use bus_mapping::{ @@ -17,6 +18,14 @@ use halo2_proofs::{ }; use mock::{test_ctx::helpers::account_0_code_account_1_no_code, TestContext, MOCK_ACCOUNTS}; +#[test] +fn copy_circuit_unusable_rows() { + assert_eq!( + CopyCircuit::::unusable_rows(), + unusable_rows::>(), + ) +} + /// Test copy circuit from copy events and test data pub fn test_copy_circuit( k: u32, diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 19f198486f..3144697a47 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -19,6 +19,7 @@ pub use self::EvmCircuit as TestEvmCircuit; pub use crate::witness; use crate::{ + evm_circuit::param::{MAX_STEP_HEIGHT, STEP_STATE_HEIGHT}, table::{ BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, LookupTable, RwTable, TxTable, }, @@ -233,6 +234,12 @@ impl EvmCircuit { impl SubCircuit for EvmCircuit { type Config = EvmCircuitConfig; + fn unusable_rows() -> usize { + // Most columns are queried at MAX_STEP_HEIGHT + STEP_STATE_HEIGHT distinct rotations, so + // returns (MAX_STEP_HEIGHT + STEP_STATE_HEIGHT + 3) unusable rows. + MAX_STEP_HEIGHT + STEP_STATE_HEIGHT + 3 + } + fn new_from_block(block: &witness::Block) -> Self { Self::new(block.clone()) } @@ -439,6 +446,7 @@ mod evm_circuit_stats { }, stats::print_circuit_stats_by_states, test_util::CircuitTestBuilder, + util::{unusable_rows, SubCircuit}, witness::block_convert, }; use bus_mapping::{circuit_input_builder::CircuitsParams, mock::BlockData}; @@ -458,6 +466,14 @@ mod evm_circuit_stats { MOCK_ACCOUNTS, }; + #[test] + fn evm_circuit_unusable_rows() { + assert_eq!( + EvmCircuit::::unusable_rows(), + unusable_rows::>(), + ) + } + #[test] pub fn empty_evm_circuit_no_padding() { CircuitTestBuilder::new_from_test_ctx( diff --git a/zkevm-circuits/src/exp_circuit.rs b/zkevm-circuits/src/exp_circuit.rs index 2bd2c05aaa..5b895ac1db 100644 --- a/zkevm-circuits/src/exp_circuit.rs +++ b/zkevm-circuits/src/exp_circuit.rs @@ -496,6 +496,29 @@ impl ExpCircuit { impl SubCircuit for ExpCircuit { type Config = ExpCircuitConfig; + fn unusable_rows() -> usize { + // Column base_limb of ExpTable is queried at 8 distinct rotations at + // - Rotation(0) + // - Rotation(1) + // - Rotation(2) + // - Rotation(3) + // - Rotation(7) + // - Rotation(8) + // - Rotation(9) + // - Rotation(10) + // Also column col2 and col3 of are queried at 8 distinct rotations at + // - Rotation(0) + // - Rotation(1) + // - Rotation(2) + // - Rotation(3) + // - Rotation(4) + // - Rotation(5) + // - Rotation(6) + // - Rotation(9) + // so returns 11 unusable rows. + 11 + } + fn new_from_block(block: &witness::Block) -> Self { // Hardcoded to pass unit tests for now. In the future, insert: // "block.circuits_params.max_exp_rows" diff --git a/zkevm-circuits/src/exp_circuit/test.rs b/zkevm-circuits/src/exp_circuit/test.rs index ac168f7890..2df199f217 100644 --- a/zkevm-circuits/src/exp_circuit/test.rs +++ b/zkevm-circuits/src/exp_circuit/test.rs @@ -2,6 +2,7 @@ use crate::{ evm_circuit::witness::{block_convert, Block}, exp_circuit::ExpCircuit, + util::{unusable_rows, SubCircuit}, }; use bus_mapping::{ circuit_input_builder::{CircuitInputBuilder, CircuitsParams}, @@ -14,6 +15,14 @@ use halo2_proofs::{ }; use mock::TestContext; +#[test] +fn exp_circuit_unusable_rows() { + assert_eq!( + ExpCircuit::::unusable_rows(), + unusable_rows::>(), + ) +} + /// Test exponentiation circuit with the provided block witness pub fn test_exp_circuit(k: u32, block: Block) { let circuit = ExpCircuit::::new( diff --git a/zkevm-circuits/src/keccak_circuit.rs b/zkevm-circuits/src/keccak_circuit.rs index 8cbcb06e21..c2088a174c 100644 --- a/zkevm-circuits/src/keccak_circuit.rs +++ b/zkevm-circuits/src/keccak_circuit.rs @@ -19,7 +19,7 @@ pub use KeccakCircuitConfig as KeccakConfig; use self::{ cell_manager::*, - keccak_packed_multi::{multi_keccak, KeccakRow}, + keccak_packed_multi::{keccak_unusable_rows, multi_keccak, KeccakRow}, param::*, table::*, util::*, @@ -982,6 +982,10 @@ pub struct KeccakCircuit { impl SubCircuit for KeccakCircuit { type Config = KeccakCircuitConfig; + fn unusable_rows() -> usize { + keccak_unusable_rows() + } + /// The `block.circuits_params.keccak_padding` parmeter, when enabled, sets /// up the circuit to support a fixed number of permutations/keccak_f's, /// independently of the permutations required by `inputs`. diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index 5f5175edb7..903de1f3a4 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -11,11 +11,19 @@ use std::{env::var, vec}; pub(crate) fn get_num_rows_per_round() -> usize { var("KECCAK_ROWS") - .unwrap_or_else(|_| "12".to_string()) + .unwrap_or_else(|_| format!("{DEFAULT_KECCAK_ROWS}")) .parse() .expect("Cannot parse KECCAK_ROWS env var as usize") } +pub(crate) fn keccak_unusable_rows() -> usize { + const UNUSABLE_ROWS_BY_KECCAK_ROWS: [usize; 24] = [ + 53, 67, 63, 59, 45, 79, 77, 75, 73, 71, 69, 67, 65, 63, 61, 59, 57, 71, 89, 107, 107, 107, + 107, 107, + ]; + UNUSABLE_ROWS_BY_KECCAK_ROWS[get_num_rows_per_round() - NUM_BYTES_PER_WORD - 1] +} + pub(crate) fn get_num_bits_per_absorb_lookup() -> usize { get_num_bits_per_lookup(ABSORB_LOOKUP_RANGE) } diff --git a/zkevm-circuits/src/keccak_circuit/param.rs b/zkevm-circuits/src/keccak_circuit/param.rs index 121fe9ab36..847c10e8e6 100644 --- a/zkevm-circuits/src/keccak_circuit/param.rs +++ b/zkevm-circuits/src/keccak_circuit/param.rs @@ -1,4 +1,5 @@ pub(crate) const MAX_DEGREE: usize = 9; +pub(crate) const DEFAULT_KECCAK_ROWS: usize = 12; pub(crate) const ABSORB_LOOKUP_RANGE: usize = 3; pub(crate) const THETA_C_LOOKUP_RANGE: usize = 6; pub(crate) const RHO_PI_LOOKUP_RANGE: usize = 4; diff --git a/zkevm-circuits/src/keccak_circuit/test.rs b/zkevm-circuits/src/keccak_circuit/test.rs index 31eae29303..939dad046d 100644 --- a/zkevm-circuits/src/keccak_circuit/test.rs +++ b/zkevm-circuits/src/keccak_circuit/test.rs @@ -1,5 +1,6 @@ #![allow(unused_imports)] use super::*; +use crate::util::unusable_rows; use eth_types::Field; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, @@ -12,6 +13,21 @@ use std::iter::zip; use super::util::{target_part_sizes, target_part_sizes_rot, WordParts}; +// This needs to be tested independent since it sets the environment variable +// which might affect other tests. +#[ignore] +#[test] +fn serial_keccak_circuit_unusable_rows() { + for keccak_rows in NUM_BYTES_PER_WORD + 1..=32 { + std::env::set_var("KECCAK_ROWS", format!("{keccak_rows}")); + assert_eq!( + KeccakCircuit::::unusable_rows(), + unusable_rows::>(), + ) + } + std::env::set_var("KECCAK_ROWS", format!("{DEFAULT_KECCAK_ROWS}")); +} + fn verify(k: u32, inputs: Vec>, success: bool) { let circuit = KeccakCircuit::new(2usize.pow(k), inputs); diff --git a/zkevm-circuits/src/keccak_circuit/util.rs b/zkevm-circuits/src/keccak_circuit/util.rs index d94ab8d41e..178ebe067a 100644 --- a/zkevm-circuits/src/keccak_circuit/util.rs +++ b/zkevm-circuits/src/keccak_circuit/util.rs @@ -1,6 +1,6 @@ //! Utility traits, functions used in the crate. -use super::param::*; +use super::{keccak_packed_multi::keccak_unusable_rows, param::*}; use eth_types::{Field, ToScalar, Word}; use halo2_proofs::{circuit::Value, halo2curves::FieldExt}; use std::env::var; @@ -224,7 +224,7 @@ pub(crate) fn get_num_bits_per_lookup(range: usize) -> usize { // Implementation of the above without environment dependency. pub(crate) fn get_num_bits_per_lookup_impl(range: usize, log_height: usize) -> usize { - let num_unusable_rows = 31; + let num_unusable_rows = keccak_unusable_rows(); let height = 2usize.pow(log_height as u32); let mut num_bits = 1; while range.pow(num_bits + 1) + num_unusable_rows <= height { diff --git a/zkevm-circuits/src/pi_circuit.rs b/zkevm-circuits/src/pi_circuit.rs index 0a7875837e..89222c7c2d 100644 --- a/zkevm-circuits/src/pi_circuit.rs +++ b/zkevm-circuits/src/pi_circuit.rs @@ -1141,6 +1141,16 @@ impl PiCircuit { impl SubCircuit for PiCircuit { type Config = PiCircuitConfig; + fn unusable_rows() -> usize { + // Column raw_public_inputs is queried at 4 distinct rotations at + // - Rotation::cur() + // - Rotation(BLOCK_LEN + 1 + EXTRA_LEN) + // - Rotation(BLOCK_LEN + 1 + EXTRA_LEN + max_txs * TX_LEN + 1) + // - Rotation(BLOCK_LEN + 1 + EXTRA_LEN + 2 * (max_txs * TX_LEN + 1)) + // so returns 7 unusable rows. + 7 + } + fn new_from_block(block: &witness::Block) -> Self { let public_data = PublicData { chain_id: block.context.chain_id, diff --git a/zkevm-circuits/src/pi_circuit/dev.rs b/zkevm-circuits/src/pi_circuit/dev.rs index c901fb9f58..1af92653ee 100644 --- a/zkevm-circuits/src/pi_circuit/dev.rs +++ b/zkevm-circuits/src/pi_circuit/dev.rs @@ -17,6 +17,10 @@ impl SubCircuit { type Config = PiCircuitConfig; + fn unusable_rows() -> usize { + PiCircuit::::unusable_rows() + } + fn new_from_block(block: &witness::Block) -> Self { assert_eq!(block.circuits_params.max_txs, MAX_TXS); assert_eq!(block.circuits_params.max_calldata, MAX_CALLDATA); diff --git a/zkevm-circuits/src/pi_circuit/test.rs b/zkevm-circuits/src/pi_circuit/test.rs index 0310d6a0fd..ddd453e110 100644 --- a/zkevm-circuits/src/pi_circuit/test.rs +++ b/zkevm-circuits/src/pi_circuit/test.rs @@ -1,5 +1,6 @@ #![allow(unused_imports)] use super::{dev::*, *}; +use crate::util::unusable_rows; use halo2_proofs::{ dev::{MockProver, VerifyFailure}, halo2curves::bn256::Fr, @@ -8,6 +9,16 @@ use mock::{CORRECT_MOCK_TXS, MOCK_CHAIN_ID}; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; +#[test] +fn pi_circuit_unusable_rows() { + const MAX_TXS: usize = 2; + const MAX_CALLDATA: usize = 8; + assert_eq!( + PiCircuit::::unusable_rows(), + unusable_rows::>(), + ) +} + fn run( k: u32, public_data: PublicData, diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index acbd8fd908..3ad529e4f6 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -455,6 +455,12 @@ impl SubCircuit for StateCircuit { Self::new(block.rws.clone(), block.circuits_params.max_rws) } + fn unusable_rows() -> usize { + // No column queried at more than 3 distinct rotations, so returns 6 as + // minimum unusable rows. + 6 + } + /// Return the minimum number of rows required to prove the block fn min_num_rows_block(block: &witness::Block) -> (usize, usize) { ( diff --git a/zkevm-circuits/src/state_circuit/test.rs b/zkevm-circuits/src/state_circuit/test.rs index 55bc7acfec..ac911d61b0 100644 --- a/zkevm-circuits/src/state_circuit/test.rs +++ b/zkevm-circuits/src/state_circuit/test.rs @@ -2,7 +2,7 @@ pub use super::{dev::*, *}; use crate::{ table::{AccountFieldTag, CallContextFieldTag, RwTableTag, TxLogFieldTag, TxReceiptFieldTag}, - util::SubCircuit, + util::{unusable_rows, SubCircuit}, witness::{MptUpdates, Rw, RwMap}, }; use bus_mapping::operation::{ @@ -28,6 +28,14 @@ use strum::IntoEnumIterator; const N_ROWS: usize = 1 << 16; +#[test] +fn state_circuit_unusable_rows() { + assert_eq!( + StateCircuit::::unusable_rows(), + unusable_rows::>(), + ) +} + fn test_state_circuit_ok( memory_ops: Vec>, stack_ops: Vec>, diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 9f4e55ebd3..41662a8261 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -270,6 +270,20 @@ impl; + fn unusable_rows() -> usize { + itertools::max([ + EvmCircuit::::unusable_rows(), + StateCircuit::::unusable_rows(), + TxCircuit::::unusable_rows(), + PiCircuit::::unusable_rows(), + BytecodeCircuit::::unusable_rows(), + CopyCircuit::::unusable_rows(), + ExpCircuit::::unusable_rows(), + KeccakCircuit::::unusable_rows(), + ]) + .unwrap() + } + fn new_from_block(block: &Block) -> Self { let evm_circuit = EvmCircuit::new_from_block(block); let state_circuit = StateCircuit::new_from_block(block); @@ -441,9 +455,8 @@ impl TxCircuit { impl SubCircuit for TxCircuit { type Config = TxCircuitConfig; + fn unusable_rows() -> usize { + // No column queried at more than 3 distinct rotations, so returns 6 as + // minimum unusable rows. + 6 + } + fn new_from_block(block: &witness::Block) -> Self { Self::new( block.circuits_params.max_txs, diff --git a/zkevm-circuits/src/tx_circuit/test.rs b/zkevm-circuits/src/tx_circuit/test.rs index 71ed0ce597..1c794d3f86 100644 --- a/zkevm-circuits/src/tx_circuit/test.rs +++ b/zkevm-circuits/src/tx_circuit/test.rs @@ -1,6 +1,6 @@ #![allow(unused_imports)] use super::*; -use crate::util::log2_ceil; +use crate::util::{log2_ceil, unusable_rows}; use eth_types::address; use halo2_proofs::{ dev::{MockProver, VerifyFailure}, @@ -8,7 +8,13 @@ use halo2_proofs::{ }; use mock::AddrOrWallet; -const NUM_BLINDING_ROWS: usize = 64; +#[test] +fn tx_circuit_unusable_rows() { + assert_eq!( + TxCircuit::::unusable_rows(), + unusable_rows::>(), + ) +} fn run( txs: Vec, @@ -16,7 +22,9 @@ fn run( max_txs: usize, max_calldata: usize, ) -> Result<(), Vec> { - let k = log2_ceil(NUM_BLINDING_ROWS + TxCircuit::::min_num_rows(max_txs, max_calldata)); + let k = log2_ceil( + TxCircuit::::unusable_rows() + TxCircuit::::min_num_rows(max_txs, max_calldata), + ); // SignVerifyChip -> ECDSAChip -> MainGate instance column let circuit = TxCircuit::::new(max_txs, max_calldata, chain_id, txs); diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index afb74fe5c8..3c0f591bdb 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -4,7 +4,8 @@ use halo2_proofs::{ arithmetic::FieldExt, circuit::{Layouter, Value}, plonk::{ - Challenge, ConstraintSystem, Error, Expression, FirstPhase, SecondPhase, VirtualCells, + Challenge, Circuit, ConstraintSystem, Error, Expression, FirstPhase, SecondPhase, + VirtualCells, }, }; use keccak256::plain::Keccak; @@ -158,6 +159,10 @@ pub trait SubCircuit { /// Configuration of the SubCircuit. type Config: SubCircuitConfig; + /// Returns number of unusable rows of the SubCircuit, which should be + /// `meta.blinding_factors() + 1`. + fn unusable_rows() -> usize; + /// Create a new SubCircuit from a witness Block fn new_from_block(block: &witness::Block) -> Self; @@ -212,3 +217,22 @@ pub(crate) fn get_push_size(byte: u8) -> u64 { 0u64 } } + +/// Returns number of unusable rows of the Circuit. +/// The minimum unusable rows of a circuit is currently 6, where +/// - 3 comes from minimum number of distinct queries to permutation argument witness column +/// - 1 comes from queries at x_3 during multiopen +/// - 1 comes as slight defense against off-by-one errors +/// - 1 comes from reservation for last row for grand-product boundray check, hence not copy-able or +/// lookup-able. Note this 1 is not considered in [`ConstraintSystem::blinding_factors`], so below +/// we need to add an extra 1. +/// +/// For circuit with column queried at more than 3 distinct rotation, we can +/// calculate the unusable rows as (x - 3) + 6 where x is the number of distinct +/// rotation. +pub(crate) fn unusable_rows>() -> usize { + let mut cs = ConstraintSystem::default(); + C::configure(&mut cs); + + cs.blinding_factors() + 1 +} diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index 6c42920dab..d65db2c434 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; #[cfg(any(feature = "test", test))] use crate::evm_circuit::{detect_fixed_table_tags, EvmCircuit}; -use crate::{evm_circuit::util::rlc, table::BlockContextFieldTag}; +use crate::{evm_circuit::util::rlc, table::BlockContextFieldTag, util::SubCircuit}; use bus_mapping::{ circuit_input_builder::{self, CircuitsParams, CopyEvent, ExpEvent}, Error, @@ -101,8 +101,6 @@ impl Block { .map(|e| e.steps.len() * OFFSET_INCREMENT) .sum(); - const NUM_BLINDING_ROWS: usize = 64; - let rows_needed: usize = itertools::max([ num_rows_required_for_execution_steps, num_rows_required_for_rw_table, @@ -115,7 +113,7 @@ impl Block { ]) .unwrap(); - let k = log2_ceil(NUM_BLINDING_ROWS + rows_needed); + let k = log2_ceil(EvmCircuit::::unusable_rows() + rows_needed); log::debug!( "num_rows_requred_for rw_table={}, fixed_table={}, bytecode_table={}, \ copy_table={}, keccak_table={}, tx_table={}, exp_table={}", From 22dd26396c0268ed7c7adfa236ff2d7954a9d470 Mon Sep 17 00:00:00 2001 From: Steven Date: Fri, 28 Apr 2023 19:58:45 +0800 Subject: [PATCH 018/102] Fix to handle successful run with Uint64 overflow for multiple opcodes (#1317) ### Description Fix successful run cases with Uint64 overflow for multiple opcodes. 1. Add `WordByteRangeGadget` to constrain if Word is within the specified byte range. 2. Add `WordByteCapGadget` to constrain if Word is within the specified byte range (implemented by WordByteRangeGadget) and less than a maximum cap (used to replace a WordByteRangeGadget and LtGadget). 3. Fix bus-mapping and zkevm-circuits to handle overflow cases. And add unit-tests for these cases. TODO: will try to handle memory offset overflow with zero length in another PR (try to rebase for this local PR https://github.com/scroll-tech/zkevm-circuits/pull/393) and related issue https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1301. ### Rationale Reference detailed code in `go-etherum` as: . [BLOCKHASH](https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go#L438) . [CALLDATALOAD](https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go#L285) . [CALLDATACOPY](https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go#L306) . [CODECOPY](https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go#L364) . [EXTCODECOPY](https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go#L382) . [JUMPI](https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go#L550) ### Issue Link Close https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1276 ### Type of change - [X] Bug fix (non-breaking change which fixes an issue) ### How Has This Been Tested? Add unit-test cases for Uint64 overflow values. --------- Co-authored-by: Zhang Zhuo --- .../circuit_input_builder/input_state_ref.rs | 61 ++++- bus-mapping/src/evm/opcodes/calldatacopy.rs | 70 ++--- bus-mapping/src/evm/opcodes/calldataload.rs | 132 ++++----- bus-mapping/src/evm/opcodes/codecopy.rs | 55 ++-- bus-mapping/src/evm/opcodes/extcodecopy.rs | 65 ++--- bus-mapping/src/evm/opcodes/returndatacopy.rs | 9 +- eth-types/src/evm_types/memory.rs | 18 +- .../src/evm_circuit/execution/blockhash.rs | 105 ++++--- .../src/evm_circuit/execution/calldatacopy.rs | 88 +++--- .../src/evm_circuit/execution/calldataload.rs | 258 ++++++++++-------- .../src/evm_circuit/execution/codecopy.rs | 77 +++--- .../execution/error_invalid_jump.rs | 81 ++---- .../src/evm_circuit/execution/extcodecopy.rs | 97 ++++--- .../src/evm_circuit/execution/jumpi.rs | 51 ++-- .../src/evm_circuit/util/common_gadget.rs | 120 +++++++- zkevm-circuits/src/witness/step.rs | 2 +- 16 files changed, 734 insertions(+), 555 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index 22eda3249c..d57b698904 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -20,7 +20,7 @@ use eth_types::{ evm_types::{ gas_utils::memory_expansion_gas_cost, Gas, GasCost, MemoryAddress, OpcodeId, StackAddress, }, - Address, GethExecStep, ToAddress, ToBigEndian, ToWord, Word, H256, U256, + Address, Bytecode, GethExecStep, ToAddress, ToBigEndian, ToWord, Word, H256, U256, }; use ethers_core::utils::{get_contract_address, get_create2_address}; use std::cmp::max; @@ -1348,4 +1348,63 @@ impl<'a> CircuitInputStateRef<'a> { } Ok(()) } + + /// Generate copy steps for bytecode. + pub(crate) fn gen_copy_steps_for_bytecode( + &mut self, + exec_step: &mut ExecStep, + bytecode: &Bytecode, + src_addr: u64, + dst_addr: u64, + src_addr_end: u64, + bytes_left: u64, + ) -> Result, Error> { + let mut copy_steps = Vec::with_capacity(bytes_left as usize); + for idx in 0..bytes_left { + let addr = src_addr.checked_add(idx).unwrap_or(src_addr_end); + let step = if addr < src_addr_end { + let code = bytecode.code.get(addr as usize).unwrap(); + (code.value, code.is_code) + } else { + (0, false) + }; + copy_steps.push(step); + self.memory_write(exec_step, (dst_addr + idx).into(), step.0)?; + } + + Ok(copy_steps) + } + + /// Generate copy steps for call data. + pub(crate) fn gen_copy_steps_for_call_data( + &mut self, + exec_step: &mut ExecStep, + src_addr: u64, + dst_addr: u64, + src_addr_end: u64, + bytes_left: u64, + ) -> Result, Error> { + let mut copy_steps = Vec::with_capacity(bytes_left as usize); + for idx in 0..bytes_left { + let addr = src_addr.checked_add(idx).unwrap_or(src_addr_end); + let value = if addr < src_addr_end { + let byte = + self.call_ctx()?.call_data[(addr - self.call()?.call_data_offset) as usize]; + if !self.call()?.is_root { + self.push_op( + exec_step, + RW::READ, + MemoryOp::new(self.call()?.caller_id, addr.into(), byte), + ); + } + byte + } else { + 0 + }; + copy_steps.push((value, false)); + self.memory_write(exec_step, (dst_addr + idx).into(), value)?; + } + + Ok(copy_steps) + } } diff --git a/bus-mapping/src/evm/opcodes/calldatacopy.rs b/bus-mapping/src/evm/opcodes/calldatacopy.rs index 0500131d93..238b17c993 100644 --- a/bus-mapping/src/evm/opcodes/calldatacopy.rs +++ b/bus-mapping/src/evm/opcodes/calldatacopy.rs @@ -3,7 +3,7 @@ use crate::{ circuit_input_builder::{ CircuitInputStateRef, CopyDataType, CopyEvent, ExecStep, NumberOrHash, }, - operation::{CallContextField, MemoryOp, RW}, + operation::CallContextField, Error, }; use eth_types::GethExecStep; @@ -20,13 +20,13 @@ impl Opcode for Calldatacopy { let mut exec_steps = vec![gen_calldatacopy_step(state, geth_step)?]; // reconstruction - let memory_offset = geth_step.stack.nth_last(0)?.as_u64(); - let data_offset = geth_step.stack.nth_last(1)?.as_u64(); - let length = geth_step.stack.nth_last(2)?.as_usize(); + let memory_offset = geth_step.stack.nth_last(0)?; + let data_offset = geth_step.stack.nth_last(1)?; + let length = geth_step.stack.nth_last(2)?; let call_ctx = state.call_ctx_mut()?; let memory = &mut call_ctx.memory; - memory.copy_from(memory_offset, &call_ctx.call_data, data_offset, length); + memory.copy_from(memory_offset, data_offset, length, &call_ctx.call_data); let copy_event = gen_copy_event(state, geth_step)?; state.push_copy(&mut exec_steps[0], copy_event); @@ -92,64 +92,36 @@ fn gen_calldatacopy_step( Ok(exec_step) } -fn gen_copy_steps( - state: &mut CircuitInputStateRef, - exec_step: &mut ExecStep, - src_addr: u64, - dst_addr: u64, - src_addr_end: u64, - bytes_left: u64, - is_root: bool, -) -> Result, Error> { - let mut copy_steps = Vec::with_capacity(bytes_left as usize); - for idx in 0..bytes_left { - let addr = src_addr + idx; - let value = if addr < src_addr_end { - let byte = - state.call_ctx()?.call_data[(addr - state.call()?.call_data_offset) as usize]; - if !is_root { - state.push_op( - exec_step, - RW::READ, - MemoryOp::new(state.call()?.caller_id, addr.into(), byte), - ); - } - byte - } else { - 0 - }; - copy_steps.push((value, false)); - state.memory_write(exec_step, (dst_addr + idx).into(), value)?; - } - - Ok(copy_steps) -} - fn gen_copy_event( state: &mut CircuitInputStateRef, geth_step: &GethExecStep, ) -> Result { let rw_counter_start = state.block_ctx.rwc; - let memory_offset = geth_step.stack.nth_last(0)?.as_u64(); - let data_offset = geth_step.stack.nth_last(1)?.as_u64(); + + let memory_offset = geth_step.stack.nth_last(0)?; + let data_offset = geth_step.stack.nth_last(1)?; let length = geth_step.stack.nth_last(2)?.as_u64(); let call_data_offset = state.call()?.call_data_offset; let call_data_length = state.call()?.call_data_length; - let (src_addr, src_addr_end) = ( - call_data_offset + data_offset, - call_data_offset + call_data_length, - ); + + let dst_addr = memory_offset.as_u64(); + let src_addr_end = call_data_offset.checked_add(call_data_length).unwrap(); + + // Reset start offset to end offset if overflow. + let src_addr = u64::try_from(data_offset) + .ok() + .and_then(|offset| offset.checked_add(call_data_offset)) + .unwrap_or(src_addr_end) + .min(src_addr_end); let mut exec_step = state.new_step(geth_step)?; - let copy_steps = gen_copy_steps( - state, + let copy_steps = state.gen_copy_steps_for_call_data( &mut exec_step, src_addr, - memory_offset, + dst_addr, src_addr_end, length, - state.call()?.is_root, )?; let (src_type, src_id) = if state.call()?.is_root { @@ -165,7 +137,7 @@ fn gen_copy_event( src_addr_end, dst_type: CopyDataType::Memory, dst_id: NumberOrHash::Number(state.call()?.call_id), - dst_addr: memory_offset, + dst_addr, log_id: None, rw_counter_start, bytes: copy_steps, diff --git a/bus-mapping/src/evm/opcodes/calldataload.rs b/bus-mapping/src/evm/opcodes/calldataload.rs index c75336b51b..b28ae5d07c 100644 --- a/bus-mapping/src/evm/opcodes/calldataload.rs +++ b/bus-mapping/src/evm/opcodes/calldataload.rs @@ -23,73 +23,79 @@ impl Opcode for Calldataload { let offset = geth_step.stack.nth_last(0)?; state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(0), offset)?; - let is_root = state.call()?.is_root; - if is_root { - state.call_context_read( - &mut exec_step, - state.call()?.call_id, - CallContextField::TxId, - state.tx_ctx.id().into(), + // Check if offset is Uint64 overflow. + let calldata_word = if let Ok(offset) = u64::try_from(offset) { + let is_root = state.call()?.is_root; + let call_id = state.call()?.call_id; + if is_root { + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::TxId, + state.tx_ctx.id().into(), + ); + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::CallDataLength, + state.call()?.call_data_length.into(), + ); + } else { + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::CallerId, + state.call()?.caller_id.into(), + ); + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::CallDataLength, + state.call()?.call_data_length.into(), + ); + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::CallDataOffset, + state.call()?.call_data_offset.into(), + ); + } + + let call_data_offset = state.call()?.call_data_offset; + let call_data_length = state.call()?.call_data_length; + let (src_addr, src_addr_end, caller_id, call_data) = ( + call_data_offset + offset.min(call_data_length), + call_data_offset + call_data_length, + state.call()?.caller_id, + state.call_ctx()?.call_data.to_vec(), ); - state.call_context_read( - &mut exec_step, - state.call()?.call_id, - CallContextField::CallDataLength, - state.call()?.call_data_length.into(), - ); - } else { - state.call_context_read( - &mut exec_step, - state.call()?.call_id, - CallContextField::CallerId, - state.call()?.caller_id.into(), - ); - state.call_context_read( - &mut exec_step, - state.call()?.call_id, - CallContextField::CallDataLength, - state.call()?.call_data_length.into(), - ); - state.call_context_read( - &mut exec_step, - state.call()?.call_id, - CallContextField::CallDataOffset, - state.call()?.call_data_offset.into(), - ); - } - let call = state.call()?.clone(); - let (src_addr, src_addr_end, caller_id, call_data) = ( - call.call_data_offset as usize + offset.as_usize(), - call.call_data_offset as usize + call.call_data_length as usize, - call.caller_id, - state.call_ctx()?.call_data.to_vec(), - ); - let calldata_word = (0..32) - .map(|idx| { - let addr = src_addr + idx; - if addr < src_addr_end { - let byte = call_data[addr - call.call_data_offset as usize]; - if !is_root { - // caller id as call_id - state.push_op( - &mut exec_step, - RW::READ, - MemoryOp::new(caller_id, (src_addr + idx).into(), byte), - ); + let calldata: Vec<_> = (0..32) + .map(|idx| { + let addr = src_addr.checked_add(idx).unwrap_or(src_addr_end); + if addr < src_addr_end { + let byte = call_data[(addr - call_data_offset) as usize]; + if !is_root { + state.push_op( + &mut exec_step, + RW::READ, + MemoryOp::new(caller_id, (src_addr + idx).into(), byte), + ); + } + byte + } else { + 0 } - byte - } else { - 0 - } - }) - .collect::>(); + }) + .collect(); + + U256::from_big_endian(&calldata) + } else { + // Stack push `0` as result if overflow. + U256::zero() + }; - state.stack_write( - &mut exec_step, - geth_step.stack.last_filled(), - U256::from_big_endian(&calldata_word), - )?; + state.stack_write(&mut exec_step, geth_step.stack.last_filled(), calldata_word)?; Ok(vec![exec_step]) } diff --git a/bus-mapping/src/evm/opcodes/codecopy.rs b/bus-mapping/src/evm/opcodes/codecopy.rs index cf7364d6db..578f1c733f 100644 --- a/bus-mapping/src/evm/opcodes/codecopy.rs +++ b/bus-mapping/src/evm/opcodes/codecopy.rs @@ -20,10 +20,9 @@ impl Opcode for Codecopy { let mut exec_steps = vec![gen_codecopy_step(state, geth_step)?]; // reconstruction - - let dest_offset = geth_step.stack.nth_last(0)?.as_u64(); - let code_offset = geth_step.stack.nth_last(1)?.as_u64(); - let length = geth_step.stack.nth_last(2)?.as_u64(); + let dst_offset = geth_step.stack.nth_last(0)?; + let code_offset = geth_step.stack.nth_last(1)?; + let length = geth_step.stack.nth_last(2)?; let code_hash = state.call()?.code_hash; let code = state.code(code_hash)?; @@ -31,7 +30,7 @@ impl Opcode for Codecopy { let call_ctx = state.call_ctx_mut()?; let memory = &mut call_ctx.memory; - memory.copy_from(dest_offset, &code, code_offset, length as usize); + memory.copy_from(dst_offset, code_offset, length, &code); let copy_event = gen_copy_event(state, geth_step)?; state.push_copy(&mut exec_steps[0], copy_event); @@ -65,56 +64,46 @@ fn gen_codecopy_step( Ok(exec_step) } -fn gen_copy_steps( - state: &mut CircuitInputStateRef, - exec_step: &mut ExecStep, - src_addr: u64, - dst_addr: u64, - bytes_left: u64, - bytecode: &Bytecode, -) -> Result, Error> { - let mut steps = Vec::with_capacity(bytes_left as usize); - for idx in 0..bytes_left { - let addr = src_addr + idx; - let bytecode_element = bytecode.get(addr as usize).unwrap_or_default(); - steps.push((bytecode_element.value, bytecode_element.is_code)); - state.memory_write(exec_step, (dst_addr + idx).into(), bytecode_element.value)?; - } - Ok(steps) -} - fn gen_copy_event( state: &mut CircuitInputStateRef, geth_step: &GethExecStep, ) -> Result { let rw_counter_start = state.block_ctx.rwc; - let dst_offset = geth_step.stack.nth_last(0)?.as_u64(); - let code_offset = geth_step.stack.nth_last(1)?.as_u64(); + let dst_offset = geth_step.stack.nth_last(0)?; + let code_offset = geth_step.stack.nth_last(1)?; let length = geth_step.stack.nth_last(2)?.as_u64(); let code_hash = state.call()?.code_hash; let bytecode: Bytecode = state.code(code_hash)?.into(); - let src_addr_end = bytecode.to_vec().len() as u64; + let code_size = bytecode.code.len() as u64; + + let dst_addr = dst_offset.as_u64(); + let src_addr_end = code_size; + + // Reset start offset to end offset if overflow. + let src_addr = u64::try_from(code_offset) + .unwrap_or(src_addr_end) + .min(src_addr_end); let mut exec_step = state.new_step(geth_step)?; - let copy_steps = gen_copy_steps( - state, + let copy_steps = state.gen_copy_steps_for_bytecode( &mut exec_step, - code_offset, - dst_offset, - length, &bytecode, + src_addr, + dst_addr, + src_addr_end, + length, )?; Ok(CopyEvent { src_type: CopyDataType::Bytecode, src_id: NumberOrHash::Hash(code_hash), - src_addr: code_offset, + src_addr, src_addr_end, dst_type: CopyDataType::Memory, dst_id: NumberOrHash::Number(state.call()?.call_id), - dst_addr: dst_offset, + dst_addr, log_id: None, rw_counter_start, bytes: copy_steps, diff --git a/bus-mapping/src/evm/opcodes/extcodecopy.rs b/bus-mapping/src/evm/opcodes/extcodecopy.rs index 2beaf34f12..8160bc9455 100644 --- a/bus-mapping/src/evm/opcodes/extcodecopy.rs +++ b/bus-mapping/src/evm/opcodes/extcodecopy.rs @@ -24,9 +24,9 @@ impl Opcode for Extcodecopy { // reconstruction let address = geth_steps[0].stack.nth_last(0)?.to_address(); - let dest_offset = geth_steps[0].stack.nth_last(1)?.as_u64(); - let code_offset = geth_steps[0].stack.nth_last(2)?.as_u64(); - let length = geth_steps[0].stack.nth_last(3)?.as_u64(); + let dst_offset = geth_steps[0].stack.nth_last(1)?; + let code_offset = geth_step.stack.nth_last(2)?; + let length = geth_steps[0].stack.nth_last(3)?; let (_, account) = state.sdb.get_account(&address); let code_hash = account.code_hash; @@ -35,7 +35,7 @@ impl Opcode for Extcodecopy { let call_ctx = state.call_ctx_mut()?; let memory = &mut call_ctx.memory; - memory.copy_from(dest_offset, &code, code_offset, length as usize); + memory.copy_from(dst_offset, code_offset, length, &code); let copy_event = gen_copy_event(state, geth_step)?; state.push_copy(&mut exec_steps[0], copy_event); @@ -111,39 +111,15 @@ fn gen_extcodecopy_step( Ok(exec_step) } -fn gen_copy_steps( - state: &mut CircuitInputStateRef, - exec_step: &mut ExecStep, - src_addr: u64, - dst_addr: u64, - src_addr_end: u64, - bytes_left: u64, - code: &Bytecode, -) -> Result, Error> { - let mut copy_steps = Vec::with_capacity(bytes_left as usize); - for idx in 0..bytes_left { - let addr = src_addr + idx; - let step = if addr < src_addr_end { - let code = code.code.get(addr as usize).unwrap(); - (code.value, code.is_code) - } else { - (0, false) - }; - copy_steps.push(step); - state.memory_write(exec_step, (dst_addr + idx).into(), step.0)?; - } - - Ok(copy_steps) -} - fn gen_copy_event( state: &mut CircuitInputStateRef, geth_step: &GethExecStep, ) -> Result { let rw_counter_start = state.block_ctx.rwc; + let external_address = geth_step.stack.nth_last(0)?.to_address(); - let memory_offset = geth_step.stack.nth_last(1)?.as_u64(); - let data_offset = geth_step.stack.nth_last(2)?.as_u64(); + let dst_offset = geth_step.stack.nth_last(1)?; + let code_offset = geth_step.stack.nth_last(2)?; let length = geth_step.stack.nth_last(3)?.as_u64(); let account = state.sdb.get_account(&external_address).1; @@ -154,28 +130,37 @@ fn gen_copy_event( H256::zero() }; - let code: Bytecode = if exists { + let bytecode: Bytecode = if exists { state.code(code_hash)?.into() } else { Bytecode::default() }; - let src_addr_end = code.code.len() as u64; + let code_size = bytecode.code.len() as u64; + + let dst_addr = dst_offset.as_u64(); + let src_addr_end = code_size; + + // Reset start offset to end offset if overflow. + let src_addr = u64::try_from(code_offset) + .unwrap_or(src_addr_end) + .min(src_addr_end); + let mut exec_step = state.new_step(geth_step)?; - let copy_steps = gen_copy_steps( - state, + let copy_steps = state.gen_copy_steps_for_bytecode( &mut exec_step, - data_offset, - memory_offset, + &bytecode, + src_addr, + dst_addr, src_addr_end, length, - &code, )?; + Ok(CopyEvent { - src_addr: data_offset, + src_addr, src_addr_end, src_type: CopyDataType::Bytecode, src_id: NumberOrHash::Hash(code_hash), - dst_addr: memory_offset, + dst_addr, dst_type: CopyDataType::Memory, dst_id: NumberOrHash::Number(state.call()?.call_id), log_id: None, diff --git a/bus-mapping/src/evm/opcodes/returndatacopy.rs b/bus-mapping/src/evm/opcodes/returndatacopy.rs index a0e9be1ea1..f1a14a4b16 100644 --- a/bus-mapping/src/evm/opcodes/returndatacopy.rs +++ b/bus-mapping/src/evm/opcodes/returndatacopy.rs @@ -21,17 +21,16 @@ impl Opcode for Returndatacopy { // reconstruction let geth_step = &geth_steps[0]; - let dest_offset = geth_step.stack.nth_last(0)?; - let offset = geth_step.stack.nth_last(1)?; - let size = geth_step.stack.nth_last(2)?; + let dst_offset = geth_step.stack.nth_last(0)?; + let src_offset = geth_step.stack.nth_last(1)?; + let length = geth_step.stack.nth_last(2)?; // can we reduce this clone? let return_data = state.call_ctx()?.return_data.clone(); let call_ctx = state.call_ctx_mut()?; let memory = &mut call_ctx.memory; - let length = size.as_usize(); - memory.copy_from(dest_offset.as_u64(), &return_data, offset.as_u64(), length); + memory.copy_from(dst_offset, src_offset, length, &return_data); let copy_event = gen_copy_event(state, geth_step)?; state.push_copy(&mut exec_steps[0], copy_event); diff --git a/eth-types/src/evm_types/memory.rs b/eth-types/src/evm_types/memory.rs index e782475de2..ab0e7e5eef 100644 --- a/eth-types/src/evm_types/memory.rs +++ b/eth-types/src/evm_types/memory.rs @@ -329,9 +329,21 @@ impl Memory { } /// Copy source data to memory. Used in (ext)codecopy/calldatacopy. - pub fn copy_from(&mut self, dst_offset: u64, data: &[u8], data_offset: u64, length: usize) { - // https://github.com/ethereum/go-ethereum/blob/df52967ff6080a27243569020ff64cd956fb8362/core/vm/instructions.go#L312 + pub fn copy_from(&mut self, dst_offset: Word, src_offset: Word, length: Word, data: &[u8]) { + // Reference go-ethereum `opCallDataCopy` function for defails. + // https://github.com/ethereum/go-ethereum/blob/bb4ac2d396de254898a5f44b1ea2086bfe5bd193/core/vm/instructions.go#L299 + + // `length` should be checked for overflow during gas cost calculation. + // Otherwise should return an out of gas error previously. + let length = length.as_usize(); if length != 0 { + // `dst_offset` should be within range if length is non-zero. + // https://github.com/ethereum/go-ethereum/blob/bb4ac2d396de254898a5f44b1ea2086bfe5bd193/core/vm/common.go#L37 + let dst_offset = dst_offset.as_u64(); + + // Reset data offset to the maximum value of Uint64 if overflow. + let src_offset = u64::try_from(src_offset).unwrap_or(u64::MAX); + let minimal_length = dst_offset as usize + length; self.extend_at_least(minimal_length); @@ -339,7 +351,7 @@ impl Memory { let mem_ends = mem_starts + length; let dst_slice = &mut self.0[mem_starts..mem_ends]; dst_slice.fill(0); - let data_starts = data_offset as usize; + let data_starts = src_offset as usize; let actual_length = std::cmp::min( length, data.len().checked_sub(data_starts).unwrap_or_default(), diff --git a/zkevm-circuits/src/evm_circuit/execution/blockhash.rs b/zkevm-circuits/src/evm_circuit/execution/blockhash.rs index 97af6df77b..9487951323 100644 --- a/zkevm-circuits/src/evm_circuit/execution/blockhash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/blockhash.rs @@ -4,14 +4,14 @@ use crate::{ param::N_BYTES_U64, step::ExecutionState, util::{ - common_gadget::SameContextGadget, + and, + common_gadget::{SameContextGadget, WordByteCapGadget}, constraint_builder::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::Delta, }, - from_bytes, math_gadget::LtGadget, - CachedRegion, Cell, RandomLinearCombination, Word, + CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -26,10 +26,9 @@ use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct BlockHashGadget { same_context: SameContextGadget, - block_number: RandomLinearCombination, + block_number: WordByteCapGadget, current_block_number: Cell, block_hash: Word, - block_lt: LtGadget, diff_lt: LtGadget, } @@ -39,9 +38,6 @@ impl ExecutionGadget for BlockHashGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::BLOCKHASH; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let block_number = cb.query_word_rlc(); - cb.stack_pop(block_number.expr()); - let current_block_number = cb.query_cell(); cb.block_lookup( BlockContextFieldTag::Number.expr(), @@ -49,28 +45,32 @@ impl ExecutionGadget for BlockHashGadget { current_block_number.expr(), ); - let block_lt = LtGadget::construct( - cb, - from_bytes::expr(&block_number.cells), - current_block_number.expr(), - ); + let block_number = WordByteCapGadget::construct(cb, current_block_number.expr()); + cb.stack_pop(block_number.original_word()); + + let block_hash = cb.query_word_rlc(); let diff_lt = LtGadget::construct( cb, current_block_number.expr(), - 257.expr() + from_bytes::expr(&block_number.cells), + 257.expr() + block_number.valid_value(), ); - let block_hash = cb.query_word_rlc(); - cb.condition(block_lt.expr() * diff_lt.expr(), |cb| { + let is_valid = and::expr([block_number.lt_cap(), diff_lt.expr()]); + + cb.condition(is_valid.expr(), |cb| { cb.block_lookup( BlockContextFieldTag::BlockHash.expr(), - Some(from_bytes::expr(&block_number.cells)), + Some(block_number.valid_value()), block_hash.expr(), ); }); - cb.condition(not::expr(block_lt.expr() * diff_lt.expr()), |cb| { - cb.require_zero("invalid range", block_hash.expr()); + + cb.condition(not::expr(is_valid), |cb| { + cb.require_zero( + "Invalid block number for block hash lookup", + block_hash.expr(), + ); }); cb.stack_push(block_hash.expr()); @@ -89,7 +89,6 @@ impl ExecutionGadget for BlockHashGadget { block_number, current_block_number, block_hash, - block_lt, diff_lt, } } @@ -105,29 +104,17 @@ impl ExecutionGadget for BlockHashGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; + let current_block_number = block.context.number; + let current_block_number = current_block_number + .to_scalar() + .expect("unexpected U256 -> Scalar conversion failure"); + let block_number = block.rws[step.rw_indices[0]].stack_value(); - self.block_number.assign( - region, - offset, - Some( - block_number.to_le_bytes()[..N_BYTES_U64] - .try_into() - .unwrap(), - ), - )?; - let block_number: F = block_number.to_scalar().unwrap(); + self.block_number + .assign(region, offset, block_number, current_block_number)?; - let current_block_number = block.context.number; - self.current_block_number.assign( - region, - offset, - Value::known( - current_block_number - .to_scalar() - .expect("unexpected U256 -> Scalar conversion failure"), - ), - )?; - let current_block_number: F = current_block_number.to_scalar().unwrap(); + self.current_block_number + .assign(region, offset, Value::known(current_block_number))?; self.block_hash.assign( region, @@ -135,14 +122,11 @@ impl ExecutionGadget for BlockHashGadget { Some(block.rws[step.rw_indices[1]].stack_value().to_le_bytes()), )?; - self.block_lt - .assign(region, offset, block_number, current_block_number)?; - self.diff_lt.assign( region, offset, current_block_number, - block_number + F::from(257), + F::from(u64::try_from(block_number).unwrap_or(u64::MAX)) + F::from(257), )?; Ok(()) @@ -155,7 +139,7 @@ mod test { use eth_types::{bytecode, U256}; use mock::test_ctx::{helpers::*, TestContext}; - fn test_ok(block_number: usize, current_block_number: u64) { + fn test_ok(block_number: U256, current_block_number: u64) { let code = bytecode! { PUSH32(block_number) BLOCKHASH @@ -185,21 +169,26 @@ mod test { #[test] fn blockhash_gadget_simple() { - test_ok(0, 5); - test_ok(1, 5); - test_ok(2, 5); - test_ok(3, 5); - test_ok(4, 5); - test_ok(5, 5); - test_ok(6, 5); + test_ok(0.into(), 5); + test_ok(1.into(), 5); + test_ok(2.into(), 5); + test_ok(3.into(), 5); + test_ok(4.into(), 5); + test_ok(5.into(), 5); + test_ok(6.into(), 5); } #[test] fn blockhash_gadget_large() { - test_ok(0xcafe - 257, 0xcafeu64); - test_ok(0xcafe - 256, 0xcafeu64); - test_ok(0xcafe - 1, 0xcafeu64); - test_ok(0xcafe, 0xcafeu64); - test_ok(0xcafe + 1, 0xcafeu64); + test_ok((0xcafe - 257).into(), 0xcafeu64); + test_ok((0xcafe - 256).into(), 0xcafeu64); + test_ok((0xcafe - 1).into(), 0xcafeu64); + test_ok(0xcafe.into(), 0xcafeu64); + test_ok((0xcafe + 1).into(), 0xcafeu64); + } + + #[test] + fn blockhash_gadget_block_number_overflow() { + test_ok(U256::MAX, 0xcafeu64); } } diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index 6296bb2874..216cfb15d9 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -1,17 +1,16 @@ use crate::{ evm_circuit::{ execution::ExecutionGadget, - param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, + param::{N_BYTES_MEMORY_WORD_SIZE, N_BYTES_U64}, step::ExecutionState, util::{ - common_gadget::SameContextGadget, + common_gadget::{SameContextGadget, WordByteCapGadget}, constraint_builder::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, - from_bytes, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, - not, select, CachedRegion, Cell, MemoryAddress, + not, select, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -19,7 +18,7 @@ use crate::{ util::Expr, }; use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId}; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; +use eth_types::{evm_types::GasCost, Field, ToScalar}; use halo2_proofs::{circuit::Value, plonk::Error}; use std::cmp::min; @@ -28,7 +27,7 @@ use std::cmp::min; pub(crate) struct CallDataCopyGadget { same_context: SameContextGadget, memory_address: MemoryAddressGadget, - data_offset: MemoryAddress, + data_offset: WordByteCapGadget, src_id: Cell, call_data_length: Cell, call_data_offset: Cell, // Only used in the internal call @@ -45,20 +44,19 @@ impl ExecutionGadget for CallDataCopyGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let memory_offset = cb.query_cell_phase2(); - let data_offset = cb.query_word_rlc(); + let src_id = cb.query_cell(); + let call_data_length = cb.query_cell(); + let call_data_offset = cb.query_cell(); + let length = cb.query_word_rlc(); + let memory_offset = cb.query_cell_phase2(); + let data_offset = WordByteCapGadget::construct(cb, call_data_length.expr()); // Pop memory_offset, data_offset, length from stack cb.stack_pop(memory_offset.expr()); - cb.stack_pop(data_offset.expr()); + cb.stack_pop(data_offset.original_word()); cb.stack_pop(length.expr()); - let memory_address = MemoryAddressGadget::construct(cb, memory_offset, length); - let src_id = cb.query_cell(); - let call_data_length = cb.query_cell(); - let call_data_offset = cb.query_cell(); - // Lookup the calldata_length and caller_address in Tx context table or // Call context table cb.condition(cb.curr.state.is_root.expr(), |cb| { @@ -97,6 +95,7 @@ impl ExecutionGadget for CallDataCopyGadget { // Calculate the next memory size and the gas cost for this memory // access + let memory_address = MemoryAddressGadget::construct(cb, memory_offset, length); let memory_expansion = MemoryExpansionGadget::construct(cb, [memory_address.address()]); let memory_copier_gas = MemoryCopierGasGadget::construct( cb, @@ -111,13 +110,23 @@ impl ExecutionGadget for CallDataCopyGadget { CopyDataType::Memory.expr(), ); cb.condition(memory_address.has_length(), |cb| { + // Set source start to the minimun value of data offset and call data length. + let src_addr = call_data_offset.expr() + + select::expr( + data_offset.lt_cap(), + data_offset.valid_value(), + call_data_length.expr(), + ); + + let src_addr_end = call_data_offset.expr() + call_data_length.expr(); + cb.copy_table_lookup( src_id.expr(), src_tag, cb.curr.state.call_id.expr(), CopyDataType::Memory.expr(), - call_data_offset.expr() + from_bytes::expr(&data_offset.cells), - call_data_offset.expr() + call_data_length.expr(), + src_addr, + src_addr_end, memory_address.offset(), memory_address.length(), 0.expr(), // for CALLDATACOPY rlc_acc is 0 @@ -175,15 +184,6 @@ impl ExecutionGadget for CallDataCopyGadget { let memory_address = self .memory_address .assign(region, offset, memory_offset, length)?; - self.data_offset.assign( - region, - offset, - Some( - data_offset.to_le_bytes()[..N_BYTES_MEMORY_ADDRESS] - .try_into() - .unwrap(), - ), - )?; let src_id = if call.is_root { tx.id } else { call.caller_id }; self.src_id.assign( region, @@ -202,6 +202,9 @@ impl ExecutionGadget for CallDataCopyGadget { self.call_data_offset .assign(region, offset, Value::known(F::from(call_data_offset)))?; + self.data_offset + .assign(region, offset, data_offset, F::from(call_data_length))?; + // rw_counter increase from copy lookup is `length` memory writes + a variable // number of memory reads. let copy_rwc_inc = length @@ -212,9 +215,10 @@ impl ExecutionGadget for CallDataCopyGadget { // memory reads when reading from memory of caller is capped by call_data_length // - data_offset. min( - length.low_u64(), - call_data_length - .checked_sub(data_offset.low_u64()) + length.as_u64(), + u64::try_from(data_offset) + .ok() + .and_then(|offset| call_data_length.checked_sub(offset)) .unwrap_or_default(), ) }; @@ -261,8 +265,8 @@ mod test { fn test_root_ok( call_data_length: usize, memory_offset: usize, - data_offset: usize, length: usize, + data_offset: Word, ) { let bytecode = bytecode! { PUSH32(length) @@ -300,14 +304,14 @@ mod test { call_data_offset: usize, call_data_length: usize, dst_offset: usize, - offset: usize, length: usize, + data_offset: Word, ) { let (addr_a, addr_b) = (mock::MOCK_ACCOUNTS[0], mock::MOCK_ACCOUNTS[1]); // code B gets called by code A, so the call is an internal call. let code_b = bytecode! { - .op_calldatacopy(dst_offset, offset, length) + .op_calldatacopy(dst_offset, data_offset, length) STOP }; @@ -340,25 +344,31 @@ mod test { #[test] fn calldatacopy_gadget_simple() { - test_root_ok(0x40, 0x40, 0x00, 10); - test_internal_ok(0x40, 0x40, 0xA0, 0x10, 10); + test_root_ok(0x40, 0x40, 10, 0x00.into()); + test_internal_ok(0x40, 0x40, 0xA0, 10, 0x10.into()); } #[test] fn calldatacopy_gadget_large() { - test_root_ok(0x204, 0x103, 0x102, 0x101); - test_internal_ok(0x30, 0x204, 0x103, 0x102, 0x101); + test_root_ok(0x204, 0x103, 0x101, 0x102.into()); + test_internal_ok(0x30, 0x204, 0x103, 0x101, 0x102.into()); } #[test] fn calldatacopy_gadget_out_of_bound() { - test_root_ok(0x40, 0x40, 0x20, 40); - test_internal_ok(0x40, 0x20, 0xA0, 0x28, 10); + test_root_ok(0x40, 0x40, 40, 0x20.into()); + test_internal_ok(0x40, 0x20, 0xA0, 10, 0x28.into()); } #[test] fn calldatacopy_gadget_zero_length() { - test_root_ok(0x40, 0x40, 0x00, 0); - test_internal_ok(0x40, 0x40, 0xA0, 0x10, 0); + test_root_ok(0x40, 0x40, 0, 0x00.into()); + test_internal_ok(0x40, 0x40, 0xA0, 0, 0x10.into()); + } + + #[test] + fn calldatacopy_gadget_data_offset_overflow() { + test_root_ok(0x40, 0x40, 0, Word::MAX); + test_internal_ok(0x40, 0x40, 0xA0, 0, Word::MAX); } } diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs index 6931647404..f443980188 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs @@ -1,5 +1,5 @@ use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToLittleEndian}; +use eth_types::Field; use halo2_proofs::{ circuit::Value, plonk::{Error, Expression}, @@ -7,17 +7,17 @@ use halo2_proofs::{ use crate::{ evm_circuit::{ - param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_WORD}, + param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_U64, N_BYTES_WORD}, step::ExecutionState, util::{ - common_gadget::SameContextGadget, + and, + common_gadget::{SameContextGadget, WordByteCapGadget}, constraint_builder::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::Delta, }, - from_bytes, memory_gadget::BufferReaderGadget, - not, CachedRegion, Cell, MemoryAddress, + not, select, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -37,8 +37,6 @@ pub(crate) struct CallDataLoadGadget { /// Source of data, this is transaction ID for a root call and caller ID for /// an internal call. src_id: Cell, - /// The bytes offset in calldata, from which we load a 32-bytes word. - offset: MemoryAddress, /// The size of the call's data (tx input for a root call or calldata length /// of an internal call). call_data_length: Cell, @@ -46,6 +44,9 @@ pub(crate) struct CallDataLoadGadget { /// tx data starts at the first byte, but can be non-zero offset for an /// internal call. call_data_offset: Cell, + /// The bytes offset in calldata, from which we load a 32-bytes word. It + /// is valid if within range of Uint64 and less than call_data_length. + data_offset: WordByteCapGadget, /// Gadget to read from tx calldata, which we validate against the word /// pushed to stack. buffer_reader: BufferReaderGadget, @@ -59,61 +60,84 @@ impl ExecutionGadget for CallDataLoadGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - let offset = cb.query_word_rlc(); - - // Pop the offset value from stack. - cb.stack_pop(offset.expr()); - - // Add a lookup constrain for TxId in the RW table. let src_id = cb.query_cell(); let call_data_length = cb.query_cell(); let call_data_offset = cb.query_cell(); - let src_addr = from_bytes::expr(&offset.cells) + call_data_offset.expr(); - let src_addr_end = call_data_length.expr() + call_data_offset.expr(); + let data_offset = WordByteCapGadget::construct(cb, call_data_length.expr()); + cb.stack_pop(data_offset.original_word()); + + cb.condition( + and::expr([data_offset.not_overflow(), cb.curr.state.is_root.expr()]), + |cb| { + cb.call_context_lookup( + false.expr(), + None, + CallContextFieldTag::TxId, + src_id.expr(), + ); + cb.call_context_lookup( + false.expr(), + None, + CallContextFieldTag::CallDataLength, + call_data_length.expr(), + ); + cb.require_equal( + "if is_root then call_data_offset == 0", + call_data_offset.expr(), + 0.expr(), + ); + }, + ); - cb.condition(cb.curr.state.is_root.expr(), |cb| { - cb.call_context_lookup(false.expr(), None, CallContextFieldTag::TxId, src_id.expr()); - cb.call_context_lookup( - false.expr(), - None, - CallContextFieldTag::CallDataLength, - call_data_length.expr(), - ); - cb.require_equal( - "if is_root then call_data_offset == 0", - call_data_offset.expr(), - 0.expr(), - ); - }); - cb.condition(not::expr(cb.curr.state.is_root.expr()), |cb| { - cb.call_context_lookup( - false.expr(), - None, - CallContextFieldTag::CallerId, - src_id.expr(), - ); - cb.call_context_lookup( - false.expr(), - None, - CallContextFieldTag::CallDataLength, + cb.condition( + and::expr([ + data_offset.not_overflow(), + not::expr(cb.curr.state.is_root.expr()), + ]), + |cb| { + cb.call_context_lookup( + false.expr(), + None, + CallContextFieldTag::CallerId, + src_id.expr(), + ); + cb.call_context_lookup( + false.expr(), + None, + CallContextFieldTag::CallDataLength, + call_data_length.expr(), + ); + cb.call_context_lookup( + false.expr(), + None, + CallContextFieldTag::CallDataOffset, + call_data_offset.expr(), + ); + }, + ); + + // Set source start to the minimun value of data offset and call data length. + let src_addr = call_data_offset.expr() + + select::expr( + data_offset.lt_cap(), + data_offset.valid_value(), call_data_length.expr(), ); - cb.call_context_lookup( - false.expr(), - None, - CallContextFieldTag::CallDataOffset, - call_data_offset.expr(), - ); - }); - let buffer_reader = BufferReaderGadget::construct(cb, src_addr.clone(), src_addr_end); + let src_addr_end = call_data_offset.expr() + call_data_length.expr(); + + let buffer_reader = BufferReaderGadget::construct(cb, src_addr.expr(), src_addr_end); - let mut calldata_word = (0..N_BYTES_WORD) + let mut calldata_word: Vec<_> = (0..N_BYTES_WORD) .map(|idx| { - // for a root call, the call data comes from tx's data field. + // For a root call, the call data comes from tx's data field. cb.condition( - cb.curr.state.is_root.expr() * buffer_reader.read_flag(idx), + and::expr([ + data_offset.not_overflow(), + buffer_reader.read_flag(idx), + cb.curr.state.is_root.expr(), + ]), |cb| { cb.tx_context_lookup( src_id.expr(), @@ -123,9 +147,13 @@ impl ExecutionGadget for CallDataLoadGadget { ); }, ); - // for an internal call, the call data comes from memory. + // For an internal call, the call data comes from memory. cb.condition( - (1.expr() - cb.curr.state.is_root.expr()) * buffer_reader.read_flag(idx), + and::expr([ + data_offset.not_overflow(), + buffer_reader.read_flag(idx), + not::expr(cb.curr.state.is_root.expr()), + ]), |cb| { cb.memory_lookup( 0.expr(), @@ -137,7 +165,7 @@ impl ExecutionGadget for CallDataLoadGadget { ); buffer_reader.byte(idx) }) - .collect::>>(); + .collect(); // Since the stack items are in little endian form, we reverse the bytes // here. @@ -146,7 +174,13 @@ impl ExecutionGadget for CallDataLoadGadget { // Add a lookup constraint for the 32-bytes that should have been pushed // to the stack. let calldata_word: [Expression; N_BYTES_WORD] = calldata_word.try_into().unwrap(); - cb.stack_push(cb.word_rlc(calldata_word)); + let calldata_word = cb.word_rlc(calldata_word); + cb.require_zero( + "Stack push result must be 0 if stack pop offset is Uint64 overflow", + data_offset.overflow() * calldata_word.expr(), + ); + + cb.stack_push(calldata_word); let step_state_transition = StepStateTransition { rw_counter: Delta(cb.rw_counter_offset()), @@ -160,10 +194,10 @@ impl ExecutionGadget for CallDataLoadGadget { Self { same_context, - offset, src_id, call_data_length, call_data_offset, + data_offset, buffer_reader, } } @@ -179,62 +213,58 @@ impl ExecutionGadget for CallDataLoadGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - // set the value for bytes offset in calldata. This is where we start - // reading bytes from. - let data_offset = block.rws[step.rw_indices[0]].stack_value(); - - // assign the calldata start and end cells. - self.offset.assign( - region, - offset, - Some( - data_offset.to_le_bytes()[..N_BYTES_MEMORY_ADDRESS] - .try_into() - .unwrap(), - ), - )?; - - // assign to the buffer reader gadget. - let (calldata_length, calldata_offset, src_id) = if call.is_root { - (tx.call_data_length as u64, 0u64, tx.id as u64) + // Assign to the buffer reader gadget. + let (src_id, call_data_offset, call_data_length) = if call.is_root { + (tx.id, 0, tx.call_data_length as u64) } else { - ( - call.call_data_length, - call.call_data_offset, - call.caller_id as u64, - ) + (call.caller_id, call.call_data_offset, call.call_data_length) }; self.src_id - .assign(region, offset, Value::known(F::from(src_id)))?; + .assign(region, offset, Value::known(F::from(src_id as u64)))?; self.call_data_length - .assign(region, offset, Value::known(F::from(calldata_length)))?; + .assign(region, offset, Value::known(F::from(call_data_length)))?; self.call_data_offset - .assign(region, offset, Value::known(F::from(calldata_offset)))?; + .assign(region, offset, Value::known(F::from(call_data_offset)))?; - let mut calldata_bytes = vec![0u8; N_BYTES_WORD]; - let (src_addr, src_addr_end) = ( - data_offset.as_usize() + calldata_offset as usize, - calldata_length as usize + calldata_offset as usize, - ); + let data_offset = block.rws[step.rw_indices[0]].stack_value(); + let offset_not_overflow = + self.data_offset + .assign(region, offset, data_offset, F::from(call_data_length))?; - for (i, byte) in calldata_bytes.iter_mut().enumerate() { - if call.is_root { - // fetch from tx call data - if src_addr + i < tx.call_data_length { - *byte = tx.call_data[src_addr + i]; - } - } else { - // fetch from memory - if src_addr + i < (call.call_data_offset + call.call_data_length) as usize { - *byte = block.rws[step.rw_indices[OFFSET_RW_MEMORY_INDICES + i]].memory_value(); + let data_offset = if offset_not_overflow { + data_offset.as_u64() + } else { + call_data_length + }; + let src_addr_end = call_data_offset + call_data_length; + let src_addr = call_data_offset + .checked_add(data_offset) + .unwrap_or(src_addr_end) + .min(src_addr_end); + + let mut calldata_bytes = vec![0u8; N_BYTES_WORD]; + if offset_not_overflow { + for (i, byte) in calldata_bytes.iter_mut().enumerate() { + if call.is_root { + // Fetch from tx call data. + if src_addr + (i as u64) < tx.call_data_length as u64 { + *byte = tx.call_data[src_addr as usize + i]; + } + } else { + // Fetch from memory. + if src_addr + (i as u64) < call.call_data_offset + call.call_data_length { + *byte = + block.rws[step.rw_indices[OFFSET_RW_MEMORY_INDICES + i]].memory_value(); + } } } } + self.buffer_reader.assign( region, offset, - src_addr as u64, - src_addr_end as u64, + src_addr, + src_addr_end, &calldata_bytes, &[true; N_BYTES_WORD], )?; @@ -249,15 +279,15 @@ mod test { use eth_types::{bytecode, Word}; use mock::{generate_mock_call_bytecode, MockCallBytecodeParams, TestContext}; - fn test_bytecode(offset: usize) -> eth_types::Bytecode { + fn test_bytecode(offset: Word) -> eth_types::Bytecode { bytecode! { - PUSH32(Word::from(offset)) + PUSH32(offset) CALLDATALOAD STOP } } - fn test_root_ok(offset: usize) { + fn test_root_ok(offset: Word) { let bytecode = test_bytecode(offset); CircuitTestBuilder::new_from_test_ctx( @@ -266,7 +296,7 @@ mod test { .run(); } - fn test_internal_ok(call_data_length: usize, call_data_offset: usize, offset: usize) { + fn test_internal_ok(call_data_length: usize, call_data_offset: usize, offset: Word) { let (addr_a, addr_b) = (mock::MOCK_ACCOUNTS[0], mock::MOCK_ACCOUNTS[1]); // code B gets called by code A, so the call is an internal call. @@ -300,17 +330,23 @@ mod test { #[test] fn calldataload_gadget_root() { - test_root_ok(0x00); - test_root_ok(0x08); - test_root_ok(0x10); - test_root_ok(0x2010); + test_root_ok(0x00.into()); + test_root_ok(0x08.into()); + test_root_ok(0x10.into()); + test_root_ok(0x2010.into()); } #[test] fn calldataload_gadget_internal() { - test_internal_ok(0x20, 0x00, 0x00); - test_internal_ok(0x20, 0x10, 0x10); - test_internal_ok(0x40, 0x20, 0x08); - test_internal_ok(0x1010, 0xff, 0x10); + test_internal_ok(0x20, 0x00, 0x00.into()); + test_internal_ok(0x20, 0x10, 0x10.into()); + test_internal_ok(0x40, 0x20, 0x08.into()); + test_internal_ok(0x1010, 0xff, 0x10.into()); + } + + #[test] + fn calldataload_gadget_offset_overflow() { + test_root_ok(Word::MAX); + test_internal_ok(0x1010, 0xff, Word::MAX); } } diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index 17a8258d47..f875c83f48 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -1,19 +1,18 @@ use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId}; -use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; +use eth_types::{evm_types::GasCost, Field, ToScalar}; use halo2_proofs::{circuit::Value, plonk::Error}; use crate::{ evm_circuit::{ - param::{N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, + param::{N_BYTES_MEMORY_WORD_SIZE, N_BYTES_U64}, step::ExecutionState, util::{ - common_gadget::SameContextGadget, + common_gadget::{SameContextGadget, WordByteCapGadget}, constraint_builder::{ ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition, }, - from_bytes, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, - not, CachedRegion, Cell, MemoryAddress, + not, select, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -25,8 +24,9 @@ use super::ExecutionGadget; #[derive(Clone, Debug)] pub(crate) struct CodeCopyGadget { same_context: SameContextGadget, - /// Holds the memory address for the offset in code from where we read. - code_offset: MemoryAddress, + /// Holds the memory address for the offset in code from where we + /// read. It is valid if within range of Uint64 and less than code_size. + code_offset: WordByteCapGadget, /// Holds the size of the current environment's bytecode. code_size: Cell, /// The code from current environment is copied to memory. To verify this @@ -51,14 +51,15 @@ impl ExecutionGadget for CodeCopyGadget { fn configure(cb: &mut EVMConstraintBuilder) -> Self { let opcode = cb.query_cell(); - // Query elements to be popped from the stack. - let dst_memory_offset = cb.query_cell_phase2(); - let code_offset = cb.query_word_rlc(); + let code_size = cb.query_cell(); + let size = cb.query_word_rlc(); + let dst_memory_offset = cb.query_cell_phase2(); + let code_offset = WordByteCapGadget::construct(cb, code_size.expr()); // Pop items from stack. cb.stack_pop(dst_memory_offset.expr()); - cb.stack_pop(code_offset.expr()); + cb.stack_pop(code_offset.original_word()); cb.stack_pop(size.expr()); // Construct memory address in the destionation (memory) to which we copy code. @@ -68,7 +69,6 @@ impl ExecutionGadget for CodeCopyGadget { let code_hash = cb.curr.state.code_hash.clone(); // Fetch the bytecode length from the bytecode table. - let code_size = cb.query_cell(); cb.bytecode_length(code_hash.expr(), code_size.expr()); // Calculate the next memory size and the gas cost for this memory @@ -83,12 +83,19 @@ impl ExecutionGadget for CodeCopyGadget { let copy_rwc_inc = cb.query_cell(); cb.condition(dst_memory_addr.has_length(), |cb| { + // Set source start to the minimun value of code offset and code size. + let src_addr = select::expr( + code_offset.lt_cap(), + code_offset.valid_value(), + code_size.expr(), + ); + cb.copy_table_lookup( code_hash.expr(), CopyDataType::Bytecode.expr(), cb.curr.state.call_id.expr(), CopyDataType::Memory.expr(), - from_bytes::expr(&code_offset.cells), + src_addr, code_size.expr(), dst_memory_addr.offset(), dst_memory_addr.length(), @@ -147,26 +154,17 @@ impl ExecutionGadget for CodeCopyGadget { let [dest_offset, code_offset, size] = [0, 1, 2].map(|i| block.rws[step.rw_indices[i]].stack_value()); - // assign the code offset memory address. - self.code_offset.assign( - region, - offset, - Some( - code_offset.to_le_bytes()[..N_BYTES_MEMORY_ADDRESS] - .try_into() - .unwrap(), - ), - )?; - - let code = block + let bytecode = block .bytecodes .get(&call.code_hash) .expect("could not find current environment's bytecode"); - self.code_size.assign( - region, - offset, - Value::known(F::from(code.bytes.len() as u64)), - )?; + + let code_size = bytecode.bytes.len() as u64; + self.code_size + .assign(region, offset, Value::known(F::from(code_size)))?; + + self.code_offset + .assign(region, offset, code_offset, F::from(code_size))?; // assign the destination memory offset. let memory_address = self @@ -202,16 +200,16 @@ mod tests { use eth_types::{bytecode, Word}; use mock::TestContext; - fn test_ok(memory_offset: usize, code_offset: usize, size: usize, large: bool) { + fn test_ok(code_offset: Word, memory_offset: usize, size: usize, large: bool) { let mut code = bytecode! {}; if large { - for _ in 0..0x101 { + for _ in 0..size { code.push(1, Word::from(123)); } } let tail = bytecode! { PUSH32(Word::from(size)) - PUSH32(Word::from(code_offset)) + PUSH32(code_offset) PUSH32(Word::from(memory_offset)) CODECOPY STOP @@ -226,13 +224,18 @@ mod tests { #[test] fn codecopy_gadget_simple() { - test_ok(0x00, 0x00, 0x20, false); - test_ok(0x20, 0x30, 0x30, false); - test_ok(0x10, 0x20, 0x42, false); + test_ok(0x00.into(), 0x00, 0x20, false); + test_ok(0x30.into(), 0x20, 0x30, false); + test_ok(0x20.into(), 0x10, 0x42, false); } #[test] fn codecopy_gadget_large() { - test_ok(0x103, 0x102, 0x101, true); + test_ok(0x102.into(), 0x103, 0x101, true); + } + + #[test] + fn codecopy_gadget_code_offset_overflow() { + test_ok(Word::MAX, 0x103, 0x101, true); } } diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index 2fc0f95c56..11c95302a8 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -4,30 +4,26 @@ use crate::{ param::N_BYTES_PROGRAM_COUNTER, step::ExecutionState, util::{ - and, - common_gadget::CommonErrorGadget, + common_gadget::{CommonErrorGadget, WordByteCapGadget}, constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder}, - from_bytes, - math_gadget::{IsEqualGadget, IsZeroGadget, LtGadget}, - select, sum, CachedRegion, Cell, Word, + math_gadget::{IsEqualGadget, IsZeroGadget}, + CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian, U256}; +use eth_types::{evm_types::OpcodeId, Field, U256}; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] pub(crate) struct ErrorInvalidJumpGadget { opcode: Cell, - dest_word: Word, + dest: WordByteCapGadget, code_len: Cell, value: Cell, is_code: Cell, - dest_not_overflow: IsZeroGadget, - dest_lt_code_len: LtGadget, is_jump_dest: IsEqualGadget, is_jumpi: IsEqualGadget, phase2_condition: Cell, @@ -41,14 +37,8 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorInvalidJump; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let dest_word = cb.query_word_rlc(); - let dest_not_overflow = - IsZeroGadget::construct(cb, sum::expr(&dest_word.cells[N_BYTES_PROGRAM_COUNTER..])); - let dest = select::expr( - dest_not_overflow.expr(), - from_bytes::expr(&dest_word.cells[..N_BYTES_PROGRAM_COUNTER]), - u64::MAX.expr(), - ); + let code_len = cb.query_cell(); + let dest = WordByteCapGadget::construct(cb, code_len.expr()); let opcode = cb.query_cell(); let value = cb.query_cell(); @@ -71,7 +61,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { let is_condition_zero = IsZeroGadget::construct(cb, phase2_condition.expr()); // Pop the value from the stack - cb.stack_pop(dest_word.expr()); + cb.stack_pop(dest.original_word()); cb.condition(is_jumpi.expr(), |cb| { cb.stack_pop(phase2_condition.expr()); @@ -80,39 +70,31 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { }); // Look up bytecode length - let code_len = cb.query_cell(); cb.bytecode_length(cb.curr.state.code_hash.expr(), code_len.expr()); - let dest_lt_code_len = LtGadget::construct(cb, dest.expr(), code_len.expr()); - // If destination is in valid range, lookup for the value. - cb.condition( - and::expr([dest_not_overflow.expr(), dest_lt_code_len.expr()]), - |cb| { - cb.bytecode_lookup( - cb.curr.state.code_hash.expr(), - dest.expr(), - is_code.expr(), - value.expr(), - ); - cb.require_zero( - "is_code is false or not JUMPDEST", - is_code.expr() * is_jump_dest.expr(), - ); - }, - ); + cb.condition(dest.lt_cap(), |cb| { + cb.bytecode_lookup( + cb.curr.state.code_hash.expr(), + dest.valid_value(), + is_code.expr(), + value.expr(), + ); + cb.require_zero( + "is_code is false or not JUMPDEST", + is_code.expr() * is_jump_dest.expr(), + ); + }); let common_error_gadget = CommonErrorGadget::construct(cb, opcode.expr(), 3.expr() + is_jumpi.expr()); Self { opcode, - dest_word, + dest, code_len, value, is_code, - dest_not_overflow, - dest_lt_code_len, is_jump_dest, is_jumpi, phase2_condition, @@ -135,10 +117,6 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; - let dest = block.rws[step.rw_indices[0]].stack_value(); - self.dest_word - .assign(region, offset, Some(dest.to_le_bytes()))?; - let condition = if is_jumpi { block.rws[step.rw_indices[1]].stack_value() } else { @@ -154,19 +132,11 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { self.code_len .assign(region, offset, Value::known(F::from(code_len)))?; - let dest_overflow_hi = dest.to_le_bytes()[N_BYTES_PROGRAM_COUNTER..] - .iter() - .fold(0, |acc, val| acc + u64::from(*val)); - self.dest_not_overflow - .assign(region, offset, F::from(dest_overflow_hi))?; - - let dest = if dest_overflow_hi == 0 { - dest.low_u64() - } else { - u64::MAX - }; + let dest = block.rws[step.rw_indices[0]].stack_value(); + self.dest.assign(region, offset, dest, F::from(code_len))?; // set default value in case can not find value, is_code from bytecode table + let dest = u64::try_from(dest).unwrap_or(code_len); let mut code_pair = [0u8, 0u8]; if dest < code_len { // get real value from bytecode table @@ -184,9 +154,6 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { F::from(OpcodeId::JUMPDEST.as_u64()), )?; - self.dest_lt_code_len - .assign(region, offset, F::from(dest), F::from(code_len))?; - self.is_jumpi.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index 01f1ac2a58..376f0f64b7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -1,16 +1,16 @@ use crate::{ evm_circuit::{ - param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_MEMORY_ADDRESS, N_BYTES_MEMORY_WORD_SIZE}, + param::{N_BYTES_ACCOUNT_ADDRESS, N_BYTES_MEMORY_WORD_SIZE, N_BYTES_U64}, step::ExecutionState, util::{ - common_gadget::SameContextGadget, + common_gadget::{SameContextGadget, WordByteCapGadget}, constraint_builder::{ ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition, }, from_bytes, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, - not, select, CachedRegion, Cell, MemoryAddress, Word, + not, select, CachedRegion, Cell, Word, }, witness::{Block, Call, ExecStep, Transaction}, }, @@ -28,7 +28,7 @@ pub(crate) struct ExtcodecopyGadget { same_context: SameContextGadget, external_address_word: Word, memory_address: MemoryAddressGadget, - data_offset: MemoryAddress, + code_offset: WordByteCapGadget, tx_id: Cell, reversion_info: ReversionInfo, is_warm: Cell, @@ -51,17 +51,17 @@ impl ExecutionGadget for ExtcodecopyGadget { let external_address = from_bytes::expr(&external_address_word.cells[..N_BYTES_ACCOUNT_ADDRESS]); - let memory_offset = cb.query_cell_phase2(); - let data_offset = cb.query_word_rlc(); + let code_size = cb.query_cell(); + let memory_length = cb.query_word_rlc(); + let memory_offset = cb.query_cell_phase2(); + let code_offset = WordByteCapGadget::construct(cb, code_size.expr()); cb.stack_pop(external_address_word.expr()); cb.stack_pop(memory_offset.expr()); - cb.stack_pop(data_offset.expr()); + cb.stack_pop(code_offset.original_word()); cb.stack_pop(memory_length.expr()); - let memory_address = MemoryAddressGadget::construct(cb, memory_offset, memory_length); - let tx_id = cb.call_context(None, CallContextFieldTag::TxId); let mut reversion_info = cb.reversion_info_read(None); let is_warm = cb.query_bool(); @@ -79,13 +79,13 @@ impl ExecutionGadget for ExtcodecopyGadget { AccountFieldTag::CodeHash, code_hash.expr(), ); - let code_size = cb.query_cell(); // TODO: If external_address doesn't exist, we will get code_hash = 0. With // this value, the bytecode_length lookup will not work, and the copy // from code_hash = 0 will not work. We should use EMPTY_HASH when // code_hash = 0. cb.bytecode_length(code_hash.expr(), code_size.expr()); + let memory_address = MemoryAddressGadget::construct(cb, memory_offset, memory_length); let memory_expansion = MemoryExpansionGadget::construct(cb, [memory_address.address()]); let memory_copier_gas = MemoryCopierGasGadget::construct( cb, @@ -101,12 +101,19 @@ impl ExecutionGadget for ExtcodecopyGadget { let copy_rwc_inc = cb.query_cell(); cb.condition(memory_address.has_length(), |cb| { + // Set source start to the minimun value of code offset and code size. + let src_addr = select::expr( + code_offset.lt_cap(), + code_offset.valid_value(), + code_size.expr(), + ); + cb.copy_table_lookup( code_hash.expr(), CopyDataType::Bytecode.expr(), cb.curr.state.call_id.expr(), CopyDataType::Memory.expr(), - from_bytes::expr(&data_offset.cells), + src_addr, code_size.expr(), memory_address.offset(), memory_address.length(), @@ -136,7 +143,7 @@ impl ExecutionGadget for ExtcodecopyGadget { same_context, external_address_word, memory_address, - data_offset, + code_offset, tx_id, is_warm, reversion_info, @@ -159,22 +166,13 @@ impl ExecutionGadget for ExtcodecopyGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let [external_address, memory_offset, data_offset, memory_length] = + let [external_address, memory_offset, code_offset, memory_length] = [0, 1, 2, 3].map(|idx| block.rws[step.rw_indices[idx]].stack_value()); self.external_address_word .assign(region, offset, Some(external_address.to_le_bytes()))?; let memory_address = self.memory_address .assign(region, offset, memory_offset, memory_length)?; - self.data_offset.assign( - region, - offset, - Some( - data_offset.to_le_bytes()[..N_BYTES_MEMORY_ADDRESS] - .try_into() - .unwrap(), - ), - )?; self.tx_id .assign(region, offset, Value::known(F::from(transaction.id as u64)))?; @@ -193,7 +191,7 @@ impl ExecutionGadget for ExtcodecopyGadget { self.code_hash .assign(region, offset, region.word_rlc(code_hash))?; - let bytecode_len = if code_hash.is_zero() { + let code_size = if code_hash.is_zero() { 0 } else { block @@ -201,10 +199,13 @@ impl ExecutionGadget for ExtcodecopyGadget { .get(&code_hash) .expect("could not find external bytecode") .bytes - .len() + .len() as u64 }; self.code_size - .assign(region, offset, Value::known(F::from(bytecode_len as u64)))?; + .assign(region, offset, Value::known(F::from(code_size)))?; + + self.code_offset + .assign(region, offset, code_offset, F::from(code_size))?; self.copy_rwc_inc.assign( region, @@ -250,8 +251,8 @@ mod test { fn test_ok( external_account: Option, + code_offset: Word, memory_offset: usize, - data_offset: usize, length: usize, is_warm: bool, ) { @@ -271,7 +272,7 @@ mod test { } code.append(&bytecode! { PUSH32(length) - PUSH32(data_offset) + PUSH32(code_offset) PUSH32(memory_offset) PUSH20(external_address.to_word()) #[start] @@ -311,8 +312,8 @@ mod test { #[test] fn extcodecopy_empty_account() { - test_ok(None, 0x00, 0x00, 0x36, true); // warm account - test_ok(None, 0x00, 0x00, 0x36, false); // cold account + test_ok(None, 0x00.into(), 0x00, 0x36, true); // warm account + test_ok(None, 0x00.into(), 0x00, 0x36, false); // cold account } #[test] @@ -323,7 +324,7 @@ mod test { code: Bytes::from([10, 40]), ..Default::default() }), - 0x00, + 0x00.into(), 0x00, 0x36, true, @@ -335,7 +336,7 @@ mod test { code: Bytes::from([10, 40]), ..Default::default() }), - 0x00, + 0x00.into(), 0x00, 0x36, false, @@ -350,7 +351,7 @@ mod test { code: Bytes::from(rand_bytes_array::<256>()), ..Default::default() }), - 0x00, + 0x00.into(), 0x00, 0x36, true, @@ -361,7 +362,7 @@ mod test { code: Bytes::from(rand_bytes_array::<256>()), ..Default::default() }), - 0x00, + 0x00.into(), 0x00, 0x36, false, @@ -376,8 +377,8 @@ mod test { code: Bytes::from(rand_bytes_array::<64>()), ..Default::default() }), + 0x20.into(), 0x00, - 0x20, 0x104, true, ); @@ -387,10 +388,36 @@ mod test { code: Bytes::from(rand_bytes_array::<64>()), ..Default::default() }), + 0x20.into(), 0x00, - 0x20, 0x104, false, ); } + + #[test] + fn extcodecopy_code_offset_overflow() { + test_ok( + Some(Account { + address: *EXTERNAL_ADDRESS, + code: Bytes::from(rand_bytes_array::<256>()), + ..Default::default() + }), + Word::MAX, + 0x00, + 0x36, + true, + ); + test_ok( + Some(Account { + address: *EXTERNAL_ADDRESS, + code: Bytes::from(rand_bytes_array::<256>()), + ..Default::default() + }), + Word::MAX, + 0x00, + 0x36, + false, + ); + } } diff --git a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs index 28d873b353..4a463bfd5a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs @@ -4,26 +4,25 @@ use crate::{ param::N_BYTES_PROGRAM_COUNTER, step::ExecutionState, util::{ - common_gadget::SameContextGadget, + common_gadget::{SameContextGadget, WordByteRangeGadget}, constraint_builder::{ - EVMConstraintBuilder, StepStateTransition, + ConstrainBuilderCommon, EVMConstraintBuilder, StepStateTransition, Transition::{Delta, To}, }, - from_bytes, math_gadget::IsZeroGadget, - select, CachedRegion, Cell, RandomLinearCombination, + select, CachedRegion, Cell, }, witness::{Block, Call, ExecStep, Transaction}, }, util::Expr, }; -use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian}; +use eth_types::{evm_types::OpcodeId, Field}; use halo2_proofs::plonk::Error; #[derive(Clone, Debug)] pub(crate) struct JumpiGadget { same_context: SameContextGadget, - destination: RandomLinearCombination, + dest: WordByteRangeGadget, phase2_condition: Cell, is_condition_zero: IsZeroGadget, } @@ -34,11 +33,11 @@ impl ExecutionGadget for JumpiGadget { const EXECUTION_STATE: ExecutionState = ExecutionState::JUMPI; fn configure(cb: &mut EVMConstraintBuilder) -> Self { - let destination = cb.query_word_rlc(); + let dest = WordByteRangeGadget::construct(cb); let phase2_condition = cb.query_cell_phase2(); // Pop the value from the stack - cb.stack_pop(destination.expr()); + cb.stack_pop(dest.original_word()); cb.stack_pop(phase2_condition.expr()); // Determine if the jump condition is met @@ -47,18 +46,20 @@ impl ExecutionGadget for JumpiGadget { // Lookup opcode at destination when should_jump cb.condition(should_jump.clone(), |cb| { - cb.opcode_lookup_at( - from_bytes::expr(&destination.cells), - OpcodeId::JUMPDEST.expr(), + cb.require_equal( + "JUMPI destination must be within range if condition is non-zero", + dest.not_overflow(), 1.expr(), ); + + cb.opcode_lookup_at(dest.valid_value(), OpcodeId::JUMPDEST.expr(), 1.expr()); }); // Transit program_counter to destination when should_jump, otherwise by // delta 1. let next_program_counter = select::expr( should_jump, - from_bytes::expr(&destination.cells), + dest.valid_value(), cb.curr.state.program_counter.expr() + 1.expr(), ); @@ -75,7 +76,7 @@ impl ExecutionGadget for JumpiGadget { Self { same_context, - destination, + dest, phase2_condition, is_condition_zero, } @@ -96,15 +97,7 @@ impl ExecutionGadget for JumpiGadget { [step.rw_indices[0], step.rw_indices[1]].map(|idx| block.rws[idx].stack_value()); let condition = region.word_rlc(condition); - self.destination.assign( - region, - offset, - Some( - destination.to_le_bytes()[..N_BYTES_PROGRAM_COUNTER] - .try_into() - .unwrap(), - ), - )?; + self.dest.assign(region, offset, destination)?; self.phase2_condition.assign(region, offset, condition)?; self.is_condition_zero .assign_value(region, offset, condition)?; @@ -174,4 +167,18 @@ mod test { test_ok(rand_range(1 << 11..0x5fff), Word::zero()); test_ok(rand_range(1 << 11..0x5fff), rand_word()); } + + #[test] + fn jumpi_gadget_with_zero_cond_and_overflow_dest() { + let bytecode = bytecode! { + PUSH32(Word::MAX) + PUSH32(Word::zero()) + JUMPI + }; + + CircuitTestBuilder::new_from_test_ctx( + TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(), + ) + .run(); + } } diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index fe2a83d81a..6858c37d56 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -1,7 +1,7 @@ use super::{ constraint_builder::ConstrainBuilderCommon, from_bytes, - math_gadget::{IsEqualGadget, IsZeroGadget}, + math_gadget::{IsEqualGadget, IsZeroGadget, LtGadget}, memory_gadget::{MemoryAddressGadget, MemoryExpansionGadget}, CachedRegion, }; @@ -1037,3 +1037,121 @@ impl CommonErrorGadget { Ok(1u64) } } + +/// Check if the passed in word is within the specified byte range +/// (not overflow) and less than a maximum cap. +#[derive(Clone, Debug)] +pub(crate) struct WordByteCapGadget { + word: WordByteRangeGadget, + lt_cap: LtGadget, +} + +impl WordByteCapGadget { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder, cap: Expression) -> Self { + let word = WordByteRangeGadget::construct(cb); + let value = select::expr(word.overflow(), cap.expr(), word.valid_value()); + let lt_cap = LtGadget::construct(cb, value, cap); + + Self { word, lt_cap } + } + + /// Return true if within the specified byte range (not overflow), false if + /// overflow. No matter whether it is less than the cap. + pub(crate) fn assign( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + original: U256, + cap: F, + ) -> Result { + let not_overflow = self.word.assign(region, offset, original)?; + + let value = if not_overflow { + let mut bytes = [0; 32]; + bytes[0..VALID_BYTES].copy_from_slice(&original.to_le_bytes()[0..VALID_BYTES]); + F::from_repr(bytes).unwrap() + } else { + cap + }; + + self.lt_cap.assign(region, offset, value, cap)?; + + Ok(not_overflow) + } + + pub(crate) fn lt_cap(&self) -> Expression { + self.lt_cap.expr() + } + + pub(crate) fn original_word(&self) -> Expression { + self.word.original_word() + } + + pub(crate) fn overflow(&self) -> Expression { + self.word.overflow() + } + + pub(crate) fn valid_value(&self) -> Expression { + self.word.valid_value() + } + + pub(crate) fn not_overflow(&self) -> Expression { + self.word.not_overflow() + } +} + +/// Check if the passed in word is within the specified byte range (not overflow). +#[derive(Clone, Debug)] +pub(crate) struct WordByteRangeGadget { + original: Word, + not_overflow: IsZeroGadget, +} + +impl WordByteRangeGadget { + pub(crate) fn construct(cb: &mut EVMConstraintBuilder) -> Self { + debug_assert!(VALID_BYTES < 32); + + let original = cb.query_word_rlc(); + let not_overflow = IsZeroGadget::construct(cb, sum::expr(&original.cells[VALID_BYTES..])); + + Self { + original, + not_overflow, + } + } + + /// Return true if within the range, false if overflow. + pub(crate) fn assign( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + original: U256, + ) -> Result { + self.original + .assign(region, offset, Some(original.to_le_bytes()))?; + + let overflow_hi = original.to_le_bytes()[VALID_BYTES..] + .iter() + .fold(0, |acc, val| acc + u64::from(*val)); + self.not_overflow + .assign(region, offset, F::from(overflow_hi))?; + + Ok(overflow_hi == 0) + } + + pub(crate) fn original_word(&self) -> Expression { + self.original.expr() + } + + pub(crate) fn overflow(&self) -> Expression { + not::expr(self.not_overflow()) + } + + pub(crate) fn valid_value(&self) -> Expression { + from_bytes::expr(&self.original.cells[..VALID_BYTES]) + } + + pub(crate) fn not_overflow(&self) -> Expression { + self.not_overflow.expr() + } +} diff --git a/zkevm-circuits/src/witness/step.rs b/zkevm-circuits/src/witness/step.rs index b4ccc4f0e1..2baa55690f 100644 --- a/zkevm-circuits/src/witness/step.rs +++ b/zkevm-circuits/src/witness/step.rs @@ -180,11 +180,11 @@ impl From<&circuit_input_builder::ExecStep> for ExecutionState { OpcodeId::CODECOPY => ExecutionState::CODECOPY, OpcodeId::CALLDATALOAD => ExecutionState::CALLDATALOAD, OpcodeId::CODESIZE => ExecutionState::CODESIZE, + OpcodeId::EXTCODECOPY => ExecutionState::EXTCODECOPY, OpcodeId::RETURN | OpcodeId::REVERT => ExecutionState::RETURN_REVERT, OpcodeId::RETURNDATASIZE => ExecutionState::RETURNDATASIZE, OpcodeId::RETURNDATACOPY => ExecutionState::RETURNDATACOPY, // dummy ops - OpcodeId::EXTCODECOPY => dummy!(ExecutionState::EXTCODECOPY), OpcodeId::CREATE => dummy!(ExecutionState::CREATE), OpcodeId::CREATE2 => dummy!(ExecutionState::CREATE2), OpcodeId::SELFDESTRUCT => dummy!(ExecutionState::SELFDESTRUCT), From e6096ca8f48bd4c73c2d8ae8fd3a98105e38abaf Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 28 Apr 2023 20:30:53 +0800 Subject: [PATCH 019/102] state machine constraints & dev-graph plots --- Cargo.lock | 3 ++ zkevm-circuits/Cargo.toml | 6 +++ zkevm-circuits/src/mpt_circuit.rs | 81 ++++++++++++++++++++++++++++++- 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7dc3f0d4b2..9101f4a280 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2059,9 +2059,11 @@ dependencies = [ "ff", "group", "halo2curves 0.3.1", + "plotters", "rand_core", "rayon", "sha3 0.9.1", + "tabbycat", "tracing", ] @@ -5045,6 +5047,7 @@ dependencies = [ "num", "num-bigint", "num_enum", + "plotters", "pretty_assertions", "rand", "rand_chacha", diff --git a/zkevm-circuits/Cargo.toml b/zkevm-circuits/Cargo.toml index c84f32ad7d..95cc868376 100644 --- a/zkevm-circuits/Cargo.toml +++ b/zkevm-circuits/Cargo.toml @@ -38,6 +38,9 @@ rand_chacha = "0.3" snark-verifier = { git = "https://github.com/privacy-scaling-explorations/snark-verifier", tag = "v2023_02_02", default-features = false, features = ["loader_halo2", "system_halo2"] } num_enum = "0.5.7" +# Developer tooling dependencies +plotters = { version = "0.3.0", optional = true } + [dev-dependencies] bus-mapping = { path = "../bus-mapping", features = ["test"] } criterion = "0.3" @@ -51,8 +54,11 @@ cli-table = "0.4" serde = { version = "1.0.130", features = ["derive"] } serde_json = "1.0.78" + + [features] default = [] test = ["ethers-signers", "mock"] test-circuits = [] warn-unimplemented = ["eth-types/warn-unimplemented"] +dev-graph = ["halo2_proofs/dev-graph", "plotters"] \ No newline at end of file diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 317bd59a6d..8f1fff1ab1 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -26,7 +26,7 @@ mod witness_row; use self::{ account_leaf::AccountLeafConfig, helpers::{key_memory, RLPItemView}, - witness_row::{ExtensionBranchRowType, Node}, + witness_row::{StartRowType,ExtensionBranchRowType, AccountRowType, StorageRowType,Node}, }; use crate::{ assign, assignf, circuit, @@ -121,6 +121,7 @@ pub struct MPTConfig { pub(crate) q_enable: Column, pub(crate) q_first: Column, pub(crate) q_last: Column, + pub(crate) rows_left_in_state: Column, pub(crate) rlp_columns: Vec>, pub(crate) managed_columns: Vec>, pub(crate) memory: Memory, @@ -177,6 +178,7 @@ impl MPTConfig { let q_enable = meta.fixed_column(); let q_first = meta.fixed_column(); let q_last = meta.fixed_column(); + let rows_left_in_state = meta.fixed_column(); let mpt_table = MptTable::construct(meta); @@ -234,20 +236,32 @@ impl MPTConfig { require!(a!(state_machine.is_start) => true); }}; // Main state machine + let sum_states = a!(state_machine.is_start) + a!(state_machine.is_branch) + a!(state_machine.is_account) + a!(state_machine.is_storage); matchx! { a!(state_machine.is_start) => { + require!(sum_states => true.expr()); + require!(f!(rows_left_in_state) => (StartRowType::Count as usize).expr()); state_machine.start_config = StartConfig::configure(meta, &mut cb, ctx.clone()); }, a!(state_machine.is_branch) => { + require!(sum_states => true.expr()); + require!(f!(rows_left_in_state) => (ExtensionBranchRowType::Count as usize ).expr()); + require!(f!(rows_left_in_state, -1) => 1.expr()); state_machine.branch_config = ExtensionBranchConfig::configure(meta, &mut cb, ctx.clone()); }, a!(state_machine.is_account) => { + require!(sum_states => true.expr()); + require!(f!(rows_left_in_state) => (AccountRowType::Count as usize).expr()); + require!(f!(rows_left_in_state, -1) => 1.expr()); state_machine.account_config = AccountLeafConfig::configure(meta, &mut cb, ctx.clone()); }, a!(state_machine.is_storage) => { + require!(sum_states => true.expr()); + require!(f!(rows_left_in_state) => (StorageRowType::Count as usize).expr()); + require!(f!(rows_left_in_state, -1) => 1.expr()); state_machine.storage_config = StorageLeafConfig::configure(meta, &mut cb, ctx.clone()); }, - _ => (), + _ => require!(sum_states => false.expr()), }; // Only account and storage rows can have lookups, disable lookups on all other rows ifx! {not!(a!(state_machine.is_account) + a!(state_machine.is_storage)) => { @@ -298,6 +312,7 @@ impl MPTConfig { q_enable, q_first, q_last, + rows_left_in_state, rlp_columns, managed_columns, memory, @@ -345,6 +360,7 @@ impl MPTConfig { is_nibbles, )?; rlp_values.push(rlp_value); + assignf!(region, (self.rows_left_in_state, offset + idx) => (node.values.len() - idx).scalar())?; } // Assign nodes @@ -612,4 +628,65 @@ mod tests { // prover.assert_satisfied(); }); } + + #[test] + fn graph_mpt() { + use plotters::prelude::*; + + let path = "src/mpt_circuit/tests"; + let files = fs::read_dir(path).unwrap(); + let files: Vec = files + .filter_map(Result::ok) + .filter(|d| { + if let Some(e) = d.path().extension() { + e == "json" + } else { + false + } + }).collect(); + + let path = &files[0].path(); + let mut parts = path.to_str().unwrap().split('-'); + parts.next(); + let file = std::fs::File::open(path.clone()); + let reader = std::io::BufReader::new(file.unwrap()); + let w: Vec> = serde_json::from_reader(reader).unwrap(); + + let randomness: Fr = 2.scalar(); + + let mut keccak_data = vec![]; + let mut witness_rows = vec![]; + for row in w.iter() { + if row[row.len() - 1] == 5 { + keccak_data.push(row[0..row.len() - 1].to_vec()); + } else { + let row = MptWitnessRow::::new(row[0..row.len()].to_vec()); + witness_rows.push(row); + } + } + let nodes = prepare_witness(&mut witness_rows); + let num_rows: usize = nodes.iter().map(|node| node.values.len()).sum(); + + let circuit = MPTCircuit:: { + nodes, + keccak_data, + randomness, + }; + + println!("Start graphing"); + + let root = BitMapBackend::new("mpt-chip-layout.png", (2048, 7680)).into_drawing_area(); + root.fill(&WHITE).unwrap(); + let root = root.titled("MPT Chip Layout", ("sans-serif", 60)).unwrap(); + + halo2_proofs::dev::CircuitLayout::default() + .render(9, &circuit, &root) + .unwrap(); + + // Generate the DOT graph string. + let dot_string = halo2_proofs::dev::circuit_dot_graph(&circuit); + print!("{}", dot_string); + + + } } From 77bc7e5cd670a2120f319c23b853c69ea0b53778 Mon Sep 17 00:00:00 2001 From: Akase Cho Date: Fri, 28 Apr 2023 21:33:15 +0800 Subject: [PATCH 020/102] handle error depth (#1155) --- bus-mapping/src/evm/opcodes.rs | 15 ++- bus-mapping/src/evm/opcodes/callop.rs | 15 +-- .../src/evm_circuit/execution/callop.rs | 96 ++++++++++++++----- zkevm-circuits/src/test_util.rs | 8 +- 4 files changed, 99 insertions(+), 35 deletions(-) diff --git a/bus-mapping/src/evm/opcodes.rs b/bus-mapping/src/evm/opcodes.rs index 076a64ef0b..8bd6df7d53 100644 --- a/bus-mapping/src/evm/opcodes.rs +++ b/bus-mapping/src/evm/opcodes.rs @@ -269,7 +269,10 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps { } } -fn fn_gen_error_state_associated_ops(error: &ExecError) -> Option { +fn fn_gen_error_state_associated_ops( + geth_step: &GethExecStep, + error: &ExecError, +) -> Option { match error { ExecError::InvalidJump => Some(InvalidJump::gen_associated_ops), ExecError::InvalidOpcode => Some(ErrorSimple::gen_associated_ops), @@ -285,7 +288,13 @@ fn fn_gen_error_state_associated_ops(error: &ExecError) -> Option Some(CallOpcode::<7>::gen_associated_ops), ExecError::WriteProtection => Some(ErrorWriteProtection::gen_associated_ops), ExecError::ReturnDataOutOfBounds => Some(ErrorReturnDataOutOfBound::gen_associated_ops), - + ExecError::Depth => { + let op = geth_step.op; + if !op.is_call() { + evm_unimplemented!("TODO: ErrDepth for CREATE is not implemented yet"); + } + Some(fn_gen_associated_ops(&op)) + } // more future errors place here _ => { evm_unimplemented!("TODO: error state {:?} not implemented", error); @@ -331,7 +340,7 @@ pub fn gen_associated_ops( // TODO: after more error state handled, refactor all error handling in // fn_gen_error_state_associated_ops method // For exceptions that have been implemented - if let Some(fn_gen_error_ops) = fn_gen_error_state_associated_ops(&exec_error) { + if let Some(fn_gen_error_ops) = fn_gen_error_state_associated_ops(geth_step, &exec_error) { return fn_gen_error_ops(state, geth_steps); } else { // For exceptions that fail to enter next call context, we need diff --git a/bus-mapping/src/evm/opcodes/callop.rs b/bus-mapping/src/evm/opcodes/callop.rs index 0310ea1ac2..c63c70e7dc 100644 --- a/bus-mapping/src/evm/opcodes/callop.rs +++ b/bus-mapping/src/evm/opcodes/callop.rs @@ -144,11 +144,14 @@ impl Opcode for CallOpcode { let caller_balance = sender_account.balance; let is_call_or_callcode = call.kind == CallKind::Call || call.kind == CallKind::CallCode; - let insufficient_balance = call.value > caller_balance && is_call_or_callcode; + + // Precheck is OK when depth is in range and caller balance is sufficient + let is_precheck_ok = + geth_step.depth < 1025 && (!is_call_or_callcode || caller_balance >= call.value); log::debug!( - "insufficient_balance: {}, call type: {:?}, sender_account: {:?} ", - insufficient_balance, + "is_precheck_ok: {}, call type: {:?}, sender_account: {:?} ", + is_precheck_ok, call.kind, call.caller_address ); @@ -169,8 +172,8 @@ impl Opcode for CallOpcode { .map(|ref addr| is_precompiled(addr)) .unwrap_or(false); // TODO: What about transfer for CALLCODE? - // Transfer value only for CALL opcode, insufficient_balance = false. - if call.kind == CallKind::Call && !insufficient_balance { + // Transfer value only for CALL opcode, is_precheck_ok = true. + if call.kind == CallKind::Call && is_precheck_ok { state.transfer( &mut exec_step, call.caller_address, @@ -216,7 +219,7 @@ impl Opcode for CallOpcode { // There are 4 branches from here. // add failure case for insufficient balance or error depth in the future. - match (insufficient_balance, is_precompile, is_empty_code_hash) { + match (!is_precheck_ok, is_precompile, is_empty_code_hash) { // 1. Call to precompiled. (false, true, _) => { assert!(call.is_success, "call to precompile should not fail"); diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index ac3fae4f3b..cdd1874a69 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -1,14 +1,15 @@ use crate::evm_circuit::{ execution::ExecutionGadget, - param::N_BYTES_GAS, + param::{N_BYTES_GAS, N_BYTES_U64}, step::ExecutionState, util::{ + and, common_gadget::{CommonCallGadget, TransferGadget}, constraint_builder::{ ConstrainBuilderCommon, EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::{Delta, To}, }, - math_gadget::{ConstantDivisionGadget, IsZeroGadget, LtWordGadget, MinMaxGadget}, + math_gadget::{ConstantDivisionGadget, IsZeroGadget, LtGadget, LtWordGadget, MinMaxGadget}, not, or, select, CachedRegion, Cell, Word, }, }; @@ -49,6 +50,7 @@ pub(crate) struct CallOpGadget { caller_balance_word: Word, // check if insufficient balance case is_insufficient_balance: LtWordGadget, + is_depth_ok: LtGadget, one_64th_gas: ConstantDivisionGadget, capped_callee_gas_left: MinMaxGadget, } @@ -87,8 +89,6 @@ impl ExecutionGadget for CallOpGadget { ) }); - cb.range_lookup(depth.expr(), 1024); - let call_gadget = CommonCallGadget::construct( cb, is_call.expr(), @@ -155,9 +155,16 @@ impl ExecutionGadget for CallOpGadget { ); let is_insufficient_balance = LtWordGadget::construct(cb, &caller_balance_word, &call_gadget.value); + // depth < 1025 + let is_depth_ok = LtGadget::construct(cb, depth.expr(), 1025.expr()); + + let is_precheck_ok = and::expr([ + is_depth_ok.expr(), + not::expr(is_insufficient_balance.expr()), + ]); // stack write is zero when is_insufficient_balance is true - cb.condition(is_insufficient_balance.expr(), |cb| { + cb.condition(not::expr(is_precheck_ok.expr()), |cb| { cb.require_zero( "stack write result is zero when is_insufficient_balance is true", call_gadget.is_success.expr(), @@ -168,19 +175,16 @@ impl ExecutionGadget for CallOpGadget { // skip the transfer (this is necessary for non-existing accounts, which // will not be crated when value is 0 and so the callee balance lookup // would be invalid). - let transfer = cb.condition( - is_call.expr() * not::expr(is_insufficient_balance.expr()), - |cb| { - TransferGadget::construct( - cb, - caller_address.expr(), - callee_address.expr(), - not::expr(call_gadget.callee_not_exists.expr()), - call_gadget.value.clone(), - &mut callee_reversion_info, - ) - }, - ); + let transfer = cb.condition(and::expr(&[is_call.expr(), is_precheck_ok.expr()]), |cb| { + TransferGadget::construct( + cb, + caller_address.expr(), + callee_address.expr(), + not::expr(call_gadget.callee_not_exists.expr()), + call_gadget.value.clone(), + &mut callee_reversion_info, + ) + }); // For CALLCODE opcode, verify caller balance is greater than or equal to stack // `value` in successful case. that is `is_insufficient_balance` is false. @@ -219,7 +223,7 @@ impl ExecutionGadget for CallOpGadget { select::expr(is_call.expr() + is_callcode.expr(), 6.expr(), 5.expr()); let memory_expansion = call_gadget.memory_expansion.clone(); cb.condition( - no_callee_code.clone() * not::expr(is_insufficient_balance.expr()), + and::expr(&[no_callee_code.expr(), is_precheck_ok.expr()]), |cb| { // Save caller's call state for field_tag in [ @@ -265,7 +269,7 @@ impl ExecutionGadget for CallOpGadget { ); // handle is_insufficient_balance step transition - cb.condition(is_insufficient_balance.expr(), |cb| { + cb.condition(not::expr(is_precheck_ok.expr()), |cb| { // Save caller's call state for field_tag in [ CallContextFieldTag::LastCalleeId, @@ -290,7 +294,7 @@ impl ExecutionGadget for CallOpGadget { }); cb.condition( - not::expr(no_callee_code) * not::expr(is_insufficient_balance.expr()), + and::expr(&[not::expr(no_callee_code), is_precheck_ok.expr()]), |cb| { // Save caller's call state for (field_tag, value) in [ @@ -421,6 +425,7 @@ impl ExecutionGadget for CallOpGadget { transfer, caller_balance_word, is_insufficient_balance, + is_depth_ok, one_64th_gas, capped_callee_gas_left, } @@ -446,6 +451,9 @@ impl ExecutionGadget for CallOpGadget { step.rw_indices[5], ] .map(|idx| block.rws[idx].call_context_value()); + let is_error_depth = depth.low_u64() > 1024; + self.is_depth_ok + .assign(region, offset, F::from(depth.low_u64()), F::from(1025))?; let stack_index = 6; // This offset is used to change the index offset of `step.rw_indices`. @@ -503,7 +511,7 @@ impl ExecutionGadget for CallOpGadget { let is_insufficient = (value > caller_balance) && (is_call || is_callcode); // only call opcode do transfer in sucessful case. let (caller_balance_pair, callee_balance_pair) = - if is_call && !is_insufficient && !value.is_zero() { + if is_call && !is_insufficient && !is_error_depth && !value.is_zero() { rw_offset += 2; ( block.rws[step.rw_indices[16 + rw_offset]].account_value_pair(), @@ -593,7 +601,7 @@ impl ExecutionGadget for CallOpGadget { callee_is_persistent.low_u64() != 0, )?; // conditionally assign - if !is_insufficient && !value.is_zero() { + if !is_insufficient && !is_error_depth && !value.is_zero() { self.transfer.assign( region, offset, @@ -632,11 +640,11 @@ mod test { use crate::test_util::CircuitTestBuilder; use bus_mapping::circuit_input_builder::CircuitsParams; use eth_types::{ - address, bytecode, evm_types::OpcodeId, geth_types::Account, Address, ToWord, Word, + address, bytecode, evm_types::OpcodeId, geth_types::Account, word, Address, ToWord, Word, }; use itertools::Itertools; - use mock::TestContext; + use mock::{test_ctx::helpers::account_0_code_account_1_no_code, TestContext}; use std::default::Default; @@ -989,4 +997,42 @@ mod test { callee(callee_bytecode), ); } + + #[test] + fn test_depth() { + let callee_code = bytecode! { + PUSH1(0x00) + PUSH1(0x00) + PUSH1(0x00) + PUSH1(0x00) + PUSH1(0x00) + ADDRESS + PUSH2(0xffff) + GAS + SUB + CALL + PUSH1(0x01) + SUB + }; + + let ctx = TestContext::<2, 1>::new( + None, + account_0_code_account_1_no_code(callee_code), + |mut txs, accs| { + txs[0] + .to(accs[0].address) + .from(accs[1].address) + .gas(word!("0x2386F26FC10000")); + }, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap(); + + CircuitTestBuilder::new_from_test_ctx(ctx) + .params(CircuitsParams { + max_rws: 300000, + ..Default::default() + }) + .run(); + } } diff --git a/zkevm-circuits/src/test_util.rs b/zkevm-circuits/src/test_util.rs index 0697c777ae..99ba2dfd56 100644 --- a/zkevm-circuits/src/test_util.rs +++ b/zkevm-circuits/src/test_util.rs @@ -8,7 +8,9 @@ use crate::{ }; use bus_mapping::{circuit_input_builder::CircuitsParams, mock::BlockData}; use eth_types::geth_types::GethData; +use std::cmp; +use crate::util::log2_ceil; use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use mock::TestContext; @@ -19,6 +21,8 @@ fn init_env_logger() { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("error")).init(); } +const NUM_BLINDING_ROWS: usize = 64; + #[allow(clippy::type_complexity)] /// Struct used to easily generate tests for EVM &| State circuits being able to /// customize all of the steps involved in the testing itself. @@ -220,9 +224,11 @@ impl CircuitTestBuilder { // TODO: use randomness as one of the circuit public input, since randomness in // state circuit and evm circuit must be same { + let rows_needed = StateCircuit::::min_num_rows_block(&block).1; + let k = cmp::max(log2_ceil(rows_needed + NUM_BLINDING_ROWS), 18); let state_circuit = StateCircuit::::new(block.rws, params.max_rws); let instance = state_circuit.instance(); - let prover = MockProver::::run(18, &state_circuit, instance).unwrap(); + let prover = MockProver::::run(k, &state_circuit, instance).unwrap(); // Skip verification of Start rows to accelerate testing let non_start_rows_len = state_circuit .rows From 4669a87cd3ce4e25e9e08d3e5a51306c60858cb5 Mon Sep 17 00:00:00 2001 From: Enrico Bottazzi <85900164+enricobottazzi@users.noreply.github.com> Date: Mon, 1 May 2023 16:22:14 +0200 Subject: [PATCH 021/102] Add Byte Range Checks in `LtChip` (#1364) ### Description Add Byte Range Checks in `LtChip`. This PR modifies the `LtChip`: - Added Fixed Column `u8` to the configuration of the chip - Added a lookup constraint between each `diff` advice column and the `u8` column - Added `load` function that assigns each integer from 0 to 255 (8bits) to the `u8` column Furthermore, the following have been applied to the tests: - In `less_than` testing, the circuit now takes `k = 9` to support a higher number of rows - In `copy_circuit` testing, the `assign_copy_events` function now calls `load` on the `lt_chip` to load the `u8` column ### Issue Link Related to #916 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) ### How Has This Been Tested? `make test-all` --------- Co-authored-by: adria0.eth <5526331+adria0@users.noreply.github.com> Co-authored-by: Chih Cheng Liang --- gadgets/src/less_than.rs | 55 ++++++++++++++++++++++++++---- zkevm-circuits/src/copy_circuit.rs | 2 ++ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/gadgets/src/less_than.rs b/gadgets/src/less_than.rs index 035e036213..0b0fd525ca 100644 --- a/gadgets/src/less_than.rs +++ b/gadgets/src/less_than.rs @@ -3,8 +3,8 @@ use eth_types::Field; use halo2_proofs::{ arithmetic::FieldExt, - circuit::{Chip, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, + circuit::{Chip, Layouter, Region, Value}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, poly::Rotation, }; @@ -23,6 +23,9 @@ pub trait LtInstruction { lhs: F, rhs: F, ) -> Result<(), Error>; + + /// Load the u8 lookup table. + fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error>; } /// Config for the Lt chip. @@ -31,8 +34,9 @@ pub struct LtConfig { /// Denotes the lt outcome. If lhs < rhs then lt == 1, otherwise lt == 0. pub lt: Column, /// Denotes the bytes representation of the difference between lhs and rhs. - /// Note that the range of each byte is not checked by this config. pub diff: [Column; N_BYTES], + /// Denotes the range within which each byte should lie. + pub u8: Column, /// Denotes the range within which both lhs and rhs lie. pub range: F, } @@ -61,6 +65,7 @@ impl LtChip { let lt = meta.advice_column(); let diff = [(); N_BYTES].map(|_| meta.advice_column()); let range = pow_of_two(N_BYTES * 8); + let u8 = meta.fixed_column(); meta.create_gate("lt gate", |meta| { let q_enable = q_enable(meta); @@ -81,7 +86,22 @@ impl LtChip { .map(move |poly| q_enable.clone() * poly) }); - LtConfig { lt, diff, range } + meta.annotate_lookup_any_column(u8, || "LOOKUP_u8"); + + diff[0..N_BYTES].iter().for_each(|column| { + meta.lookup_any("range check for u8", |meta| { + let u8_cell = meta.query_advice(*column, Rotation::cur()); + let u8_range = meta.query_fixed(u8, Rotation::cur()); + vec![(u8_cell, u8_range)] + }); + }); + + LtConfig { + lt, + diff, + range, + u8, + } } /// Constructs a Lt chip given a config. @@ -122,6 +142,25 @@ impl LtInstruction for LtChip { Ok(()) } + + fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + const RANGE: usize = 256; + + layouter.assign_region( + || "load u8 range check table", + |mut region| { + for i in 0..RANGE { + region.assign_fixed( + || "assign cell in fixed column", + self.config.u8, + i, + || Value::known(F::from(i as u64)), + )?; + } + Ok(()) + }, + ) + } } impl Chip for LtChip { @@ -157,7 +196,7 @@ mod test { // TODO: remove zk blinding factors in halo2 to restore the // correct k (without the extra + 2). - let k = usize::BITS - $values.len().leading_zeros() + 2; + let k = 9; let circuit = TestCircuit:: { values: Some($values), checks: Some($checks), @@ -174,7 +213,7 @@ mod test { // TODO: remove zk blinding factors in halo2 to restore the // correct k (without the extra + 2). - let k = usize::BITS - $values.len().leading_zeros() + 2; + let k = 9; let circuit = TestCircuit:: { values: Some($values), checks: Some($checks), @@ -258,6 +297,8 @@ mod test { let (first_value, values) = values.split_at(1); let first_value = first_value[0]; + chip.load(&mut layouter)?; + layouter.assign_region( || "witness", |mut region| { @@ -380,6 +421,8 @@ mod test { .ok_or(Error::Synthesis)?; let checks = self.checks.as_ref().ok_or(Error::Synthesis)?; + chip.load(&mut layouter)?; + layouter.assign_region( || "witness", |mut region| { diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index b746a61460..15b1a54f4b 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -513,6 +513,8 @@ impl CopyCircuitConfig { let tag_chip = BinaryNumberChip::construct(self.copy_table.tag); let lt_chip = LtChip::construct(self.addr_lt_addr_end); + lt_chip.load(layouter)?; + layouter.assign_region( || "assign copy table", |mut region| { From 7abf752526bea7718e5b1551202cbc57b7f1f757 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Wed, 3 May 2023 16:28:01 +0800 Subject: [PATCH 022/102] circuit tools updated, still need to make mpt_circuit compatible --- zkevm-circuits/src/circuit_tools.rs | 1 + .../src/circuit_tools/cached_region.rs | 242 ++++++++++++++++ .../src/circuit_tools/cell_manager.rs | 260 ++++++++++++++---- .../src/circuit_tools/constraint_builder.rs | 34 +-- zkevm-circuits/src/circuit_tools/gadgets.rs | 38 +-- zkevm-circuits/src/circuit_tools/memory.rs | 28 +- zkevm-circuits/src/evm_circuit/util.rs | 2 +- zkevm-circuits/src/mpt_circuit.rs | 9 +- zkevm-circuits/src/mpt_circuit/helpers.rs | 55 ++-- zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs | 57 ++-- zkevm-circuits/src/mpt_circuit/table.rs | 21 ++ zkevm-circuits/src/table.rs | 6 +- 12 files changed, 581 insertions(+), 172 deletions(-) create mode 100644 zkevm-circuits/src/circuit_tools/cached_region.rs create mode 100644 zkevm-circuits/src/mpt_circuit/table.rs diff --git a/zkevm-circuits/src/circuit_tools.rs b/zkevm-circuits/src/circuit_tools.rs index 25519a2ba0..677dfd33bb 100644 --- a/zkevm-circuits/src/circuit_tools.rs +++ b/zkevm-circuits/src/circuit_tools.rs @@ -2,5 +2,6 @@ #[macro_use] pub mod constraint_builder; pub mod cell_manager; +pub mod cached_region; pub mod gadgets; pub mod memory; diff --git a/zkevm-circuits/src/circuit_tools/cached_region.rs b/zkevm-circuits/src/circuit_tools/cached_region.rs new file mode 100644 index 0000000000..c1bb827d87 --- /dev/null +++ b/zkevm-circuits/src/circuit_tools/cached_region.rs @@ -0,0 +1,242 @@ +use crate::{ + circuit_tools::cell_manager::{Cell, CellType_}, + util::Challenges +}; +use bus_mapping::state_db::CodeDB; +use eth_types::{Field, ToLittleEndian, ToWord, U256}; +use halo2_proofs::{ + circuit::{AssignedCell, Region, Value}, + plonk::{Advice, Assigned, Column, Error, Expression}, + poly::Rotation, +}; +use itertools::Itertools; +use std::{ + hash::{Hash, Hasher}, +}; + +use super::cell_manager::CustomTable; + +pub struct CachedRegion<'r, 'b, F: Field> { + region: &'r mut Region<'b, F>, + advice: Vec>, + challenges: &'r Challenges>, + advice_columns: Vec>, + width_start: usize, + height_start: usize, +} + +impl<'r, 'b, F: Field> CachedRegion<'r, 'b, F> { + /// New cached region + pub(crate) fn new( + region: &'r mut Region<'b, F>, + challenges: &'r Challenges>, + advice_columns: Vec>, + height: usize, + height_start: usize, + ) -> Self { + Self { + region, + advice: vec![vec![F::zero(); height]; advice_columns.len()], + challenges, + width_start: advice_columns[0].index(), + height_start, + advice_columns, + } + } + + /// This method replicates the assignment of 1 row at height_start (which + /// must be already assigned via the CachedRegion) into a range of rows + /// indicated by offset_begin, offset_end. It can be used as a "quick" + /// path for assignment for repeated padding rows. + pub fn replicate_assignment_for_range( + &mut self, + annotation: A, + offset_begin: usize, + offset_end: usize, + ) -> Result<(), Error> + where + A: Fn() -> AR, + AR: Into, + { + for (v, column) in self + .advice + .iter() + .map(|values| values[0]) + .zip_eq(self.advice_columns.iter()) + { + if v.is_zero_vartime() { + continue; + } + let annotation: &String = &annotation().into(); + for offset in offset_begin..offset_end { + self.region + .assign_advice(|| annotation, *column, offset, || Value::known(v))?; + } + } + + Ok(()) + } + + /// Assign an advice column value (witness). + pub fn assign_advice<'v, V, VR, A, AR>( + &'v mut self, + annotation: A, + column: Column, + offset: usize, + to: V, + ) -> Result, Error> + where + V: Fn() -> Value + 'v, + for<'vr> Assigned: From<&'vr VR>, + A: Fn() -> AR, + AR: Into, + { + // Actually set the value + let res = self.region.assign_advice(annotation, column, offset, &to); + // Cache the value + // Note that the `value_field` in `AssignedCell` might be `Value::unkonwn` if + // the column has different phase than current one, so we call to `to` + // again here to cache the value. + if res.is_ok() { + to().map(|f| { + self.advice[column.index() - self.width_start][offset - self.height_start] = + Assigned::from(&f).evaluate(); + }); + } + res + } + + pub fn get_fixed(&self, _row_index: usize, _column_index: usize, _rotation: Rotation) -> F { + unimplemented!("fixed column"); + } + + pub fn get_advice(&self, row_index: usize, column_index: usize, rotation: Rotation) -> F { + self.advice[column_index - self.width_start] + [(((row_index - self.height_start) as i32) + rotation.0) as usize] + } + + pub fn challenges(&self) -> &Challenges> { + self.challenges + } + + pub fn word_rlc(&self, n: U256) -> Value { + self.challenges + .evm_word() + .map(|r| rlc::value(&n.to_le_bytes(), r)) + } + pub fn empty_code_hash_rlc(&self) -> Value { + self.word_rlc(CodeDB::empty_code_hash().to_word()) + } + + /// Constrains a cell to have a constant value. + /// + /// Returns an error if the cell is in a column where equality has not been + /// enabled. + pub fn constrain_constant( + &mut self, + cell: AssignedCell, + constant: VR, + ) -> Result<(), Error> + where + VR: Into>, + { + self.region.constrain_constant(cell.cell(), constant.into()) + } +} + +#[derive(Debug, Clone)] +pub struct StoredExpression { + pub(crate) name: String, + cell: Cell, + cell_type: CellType_, + expr: Expression, + expr_id: String, +} + +impl Hash for StoredExpression { + fn hash(&self, state: &mut H) { + self.expr_id.hash(state); + self.cell_type.hash(state); + } +} + +impl StoredExpression { + pub fn assign( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + ) -> Result, Error> { + let value = self.expr.evaluate( + &|scalar| Value::known(scalar), + &|_| unimplemented!("selector column"), + &|fixed_query| { + Value::known(region.get_fixed( + offset, + fixed_query.column_index(), + fixed_query.rotation(), + )) + }, + &|advice_query| { + Value::known(region.get_advice( + offset, + advice_query.column_index(), + advice_query.rotation(), + )) + }, + &|_| unimplemented!("instance column"), + &|challenge| *region.challenges().indexed()[challenge.index()], + &|a| -a, + &|a, b| a + b, + &|a, b| a * b, + &|a, scalar| a * Value::known(scalar), + ); + self.cell.assign(region, offset, value)?; + Ok(value) + } +} + +/// Returns the random linear combination of the inputs. +/// Encoding is done as follows: v_0 * R^0 + v_1 * R^1 + ... +pub(crate) mod rlc { + use std::ops::{Add, Mul}; + + use crate::util::Expr; + use eth_types::Field; + use halo2_proofs::plonk::Expression; + + pub(crate) fn expr>(expressions: &[E], randomness: E) -> Expression { + if !expressions.is_empty() { + generic(expressions.iter().map(|e| e.expr()), randomness.expr()) + } else { + 0.expr() + } + } + + pub(crate) fn value<'a, F: Field, I>(values: I, randomness: F) -> F + where + I: IntoIterator, + ::IntoIter: DoubleEndedIterator, + { + let values = values + .into_iter() + .map(|v| F::from(*v as u64)) + .collect::>(); + if !values.is_empty() { + generic(values, randomness) + } else { + F::zero() + } + } + + fn generic(values: I, randomness: V) -> V + where + I: IntoIterator, + ::IntoIter: DoubleEndedIterator, + V: Clone + Add + Mul, + { + let mut values = values.into_iter().rev(); + let init = values.next().expect("values should not be empty"); + + values.fold(init, |acc, value| acc * randomness.clone() + value) + } +} \ No newline at end of file diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index 9153579a75..563faa7e64 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -1,36 +1,51 @@ //! Cell manager -use crate::util::Expr; +use crate::util::{Expr, query_expression}; +use crate::circuit_tools::cached_region::CachedRegion; + use eth_types::Field; use halo2_proofs::{ - circuit::{AssignedCell, Region, Value}, - plonk::{Advice, Column, Error, Expression, VirtualCells}, + circuit::{AssignedCell, Value}, + plonk::{ConstraintSystem, Advice, Column, Error, Expression, VirtualCells}, poly::Rotation, }; +use halo2_proofs::arithmetic::FieldExt; use std::collections::BTreeMap; +use std::fmt::Debug; +use std::hash::Hash; +use strum_macros::EnumIter; -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub(crate) struct Cell { // expression for constraint - expression: Option>, - column: Option>, + expression: Expression, + column: Column, // relative position to selector for synthesis rotation: usize, + cell_column_index: usize, } + impl Cell { - pub(crate) fn new(meta: &mut VirtualCells, column: Column, rotation: usize) -> Self { + pub(crate) fn new( + meta: &mut VirtualCells, + column: Column, + rotation: usize, + cell_column_index: usize, + ) -> Self { Self { - expression: Some(meta.query_advice(column, Rotation(rotation as i32))), - column: Some(column), + expression: meta.query_advice(column, Rotation(rotation as i32)), + column, rotation, + cell_column_index, } } + pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, - value: F, + value: Value, ) -> Result, Error> { region.assign_advice( || { @@ -39,14 +54,14 @@ impl Cell { self.column, self.rotation ) }, - self.column.unwrap(), + self.column, offset + self.rotation, - || Value::known(value), + || value, ) } pub(crate) fn column(&self) -> Column { - self.column.unwrap() + self.column } pub(crate) fn rotation(&self) -> usize { @@ -54,83 +69,205 @@ impl Cell { } pub(crate) fn rot(&self, meta: &mut VirtualCells, rot: usize) -> Expression { - meta.query_advice(self.column.unwrap(), Rotation((self.rotation + rot) as i32)) + meta.query_advice(self.column, Rotation((self.rotation + rot) as i32)) } } impl Expr for Cell { fn expr(&self) -> Expression { - self.expression.as_ref().unwrap().clone() + self.expression.clone() } } impl Expr for &Cell { fn expr(&self) -> Expression { - self.expression.as_ref().unwrap().clone() + self.expression.clone() + } +} + +// #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +// pub(crate) enum CellType { +// StoragePhase1, +// StoragePhase2, +// StoragePermutation, +// LookupByte, +// Lookup(Table), +// } + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) enum CellType_ { + StoragePhase1, + StoragePhase2, + StoragePermutation, + LookupByte, + Lookup(T), +} + +pub trait CustomTable: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash { + fn matches_to(&self, other: &Self) -> bool; +} + +/// Example +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] +pub(crate) enum TestTable { + Fixed, + Tx, + Rw, + Bytecode, + Block, + Copy, + Keccak, + Exp, +} + +impl CustomTable for TestTable { + fn matches_to(&self, other: &Self) -> bool { + self == other + } +} + +fn works_like_this(table: TestTable, config: &[(TestTable, usize)]) { + if table.matches_to(&TestTable::Fixed) { + println!("matched"); } } -/// CellType -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum CellType { - /// General - Storage, + +impl CellType_ { + // The phase that given `Expression` becomes evaluateable. + fn expr_phase(expr: &Expression) -> u8 { + use Expression::*; + match expr { + Challenge(challenge) => challenge.phase() + 1, + Advice(query) => query.phase(), + Constant(_) | Selector(_) | Fixed(_) | Instance(_) => 0, + Negated(a) | Expression::Scaled(a, _) => Self::expr_phase(a), + Sum(a, b) | Product(a, b) => std::cmp::max(Self::expr_phase(a), Self::expr_phase(b)), + } + } + + /// Return the storage phase of phase + pub(crate) fn storage_for_phase(phase: u8) -> CellType_ { + match phase { + 0 => CellType_::StoragePhase1, + 1 => CellType_::StoragePhase2, + _ => unreachable!(), + } + } + + /// Return the storage cell of the expression + pub(crate) fn storage_for_expr(expr: &Expression) -> CellType_ { + Self::storage_for_phase::(Self::expr_phase::(expr)) + } } -/// CellColumn #[derive(Clone, Debug)] -pub struct CellColumn { +pub(crate) struct CellColumn { pub(crate) index: usize, - pub(crate) cell_type: CellType, + pub(crate) cell_type: CellType_, pub(crate) height: usize, pub(crate) expr: Expression, } -impl Expr for CellColumn { +impl Expr for CellColumn { fn expr(&self) -> Expression { self.expr.clone() } } -/// CellManager #[derive(Clone, Debug)] -pub struct CellManager { +pub(crate) struct CellManager { width: usize, height: usize, cells: Vec>, - columns: Vec>, - height_limit: usize, + // 对cell的抽象表示和对columns的抽象表示是分开的 + // Cell 不用 T + columns: Vec>, + phase_config: PhaseConfig, + copy_columns: usize, +} + +#[derive(Clone, Debug)] +pub struct PhaseConfig { + phase3: Vec<(T, usize)>, //lookup + phase2: usize, // rlc + phase1: usize, // byte } -impl CellManager { - pub(crate) fn new(meta: &mut VirtualCells, advice_columns: &[Column]) -> Self { +impl CellManager { + pub(crate) fn new( + meta: &mut ConstraintSystem, + height: usize, + advices: &[Column], + height_offset: usize, + phase_config: PhaseConfig, + copy_columns: usize, + ) -> Self { // Setup the columns and query the cells - let width = advice_columns.len(); - let height = 32; + let width = advices.len(); let mut cells = Vec::with_capacity(height * width); let mut columns = Vec::with_capacity(width); - for c in 0..width { - for r in 0..height { - cells.push(Cell::new(meta, advice_columns[c], r)); + + // 这个是meta.create_gate的替代 + // 主要是想 query 新的 column + // 在会加一个0.expr()为constraint,因为里面调的create_gate要求 + query_expression(meta, |meta| { + for c in 0..width { + for r in 0..height { + cells.push(Cell::new(meta, advices[c], height_offset + r, c)); + } + columns.push(CellColumn { + index: c, + cell_type: CellType_::StoragePhase1, + height: 0, + expr: cells[c * height].expr(), + }); } - columns.push(CellColumn { - index: c, - cell_type: CellType::Storage, - height: 0, - expr: cells[c * height].expr(), - }); + }); + + let mut column_idx = 0; + + // Mark columns used for lookups in Phase3 + for (table, count) in phase_config.phase3 { + for _ in 0usize..count { + columns[column_idx].cell_type = CellType_::Lookup(table); + column_idx += 1; + } + } + + // Mark columns used for Phase2 constraints + for _ in 0..phase_config.phase2 { + columns[column_idx].cell_type = CellType_::StoragePhase2; + column_idx += 1; } + // Mark columns used for byte lookup + for _ in 0..phase_config.phase1 { + columns[column_idx].cell_type = CellType_::LookupByte; + assert_eq!(advices[column_idx].column_type().phase(), 0); + column_idx += 1; + } + + // Mark columns used for copy constraints + for _ in 0..copy_columns { + meta.enable_equality(advices[column_idx]); + columns[column_idx].cell_type = CellType_::StoragePermutation; + column_idx += 1; + } + + + Self { width, height, cells, columns, - height_limit: height, + phase_config, + copy_columns, } } - pub(crate) fn query_cells(&mut self, cell_type: CellType, count: usize) -> Vec> { + pub(crate) fn query_cells(&mut self, cell_type: CellType_, count: usize) -> Vec> { let mut cells = Vec::with_capacity(count); while cells.len() < count { let column_idx = self.next_column(cell_type); @@ -141,19 +278,11 @@ impl CellManager { cells } - pub(crate) fn query_cell(&mut self, cell_type: CellType) -> Cell { + pub(crate) fn query_cell(&mut self, cell_type: CellType_) -> Cell { self.query_cells(cell_type, 1)[0].clone() } - pub(crate) fn reset(&mut self, height_limit: usize) { - assert!(height_limit <= self.height); - self.height_limit = height_limit; - for column in self.columns.iter_mut() { - column.height = 0; - } - } - - fn next_column(&self, cell_type: CellType) -> usize { + fn next_column(&self, cell_type: CellType_) -> usize { let mut best_index: Option = None; let mut best_height = self.height; for column in self.columns.iter() { @@ -162,12 +291,21 @@ impl CellManager { best_height = column.height; } } - if best_height >= self.height_limit { - best_index = None; + // Replace a CellType_::Storage by CellType_::StoragePermutation if the later has + // better height + if cell_type == CellType_::StoragePhase1 { + for column in self.columns.iter() { + if column.cell_type == CellType_::StoragePermutation && column.height < best_height { + best_index = Some(column.index); + best_height = column.height; + } + } } match best_index { Some(index) => index, - None => unreachable!("not enough cells for query: {:?}", cell_type), + // If we reach this case, it means that all the columns of cell_type have assignments + // taking self.height rows, so there's no more space. + None => panic!("not enough cells for query: {:?}", cell_type), } } @@ -180,7 +318,7 @@ impl CellManager { } /// Returns a map of CellType -> (width, height, num_cells) - pub(crate) fn get_stats(&self) -> BTreeMap { + pub(crate) fn get_stats(&self) -> BTreeMap, (usize, usize, usize)> { let mut data = BTreeMap::new(); for column in self.columns.iter() { let (mut count, mut height, mut num_cells) = @@ -193,7 +331,7 @@ impl CellManager { data } - pub(crate) fn columns(&self) -> &[CellColumn] { + pub(crate) fn columns(&self) -> &[CellColumn] { &self.columns } -} +} \ No newline at end of file diff --git a/zkevm-circuits/src/circuit_tools/constraint_builder.rs b/zkevm-circuits/src/circuit_tools/constraint_builder.rs index 5594f78214..7b02b3d444 100644 --- a/zkevm-circuits/src/circuit_tools/constraint_builder.rs +++ b/zkevm-circuits/src/circuit_tools/constraint_builder.rs @@ -7,7 +7,7 @@ use gadgets::util::{and, sum, Scalar}; use halo2_proofs::plonk::{ConstraintSystem, Expression}; use itertools::Itertools; -use super::cell_manager::{Cell, CellManager, CellType}; +use super::cell_manager::{Cell, CellManager, CellType_, CustomTable}; /// Lookup data #[derive(Clone)] @@ -24,7 +24,7 @@ pub struct LookupData { /// Constraint builder #[derive(Clone)] -pub struct ConstraintBuilder { +pub struct ConstraintBuilder { constraints: Vec<(&'static str, Expression)>, max_degree: usize, conditions: Vec>, @@ -33,11 +33,11 @@ pub struct ConstraintBuilder { /// The lookup tables pub lookup_tables: Vec>, /// CellManager - pub cell_manager: Option>, + pub cell_manager: Option>, } -impl ConstraintBuilder { - pub(crate) fn new(max_degree: usize, cell_manager: Option>) -> Self { +impl ConstraintBuilder { + pub(crate) fn new(max_degree: usize, cell_manager: Option>) -> Self { ConstraintBuilder { constraints: Vec::new(), max_degree, @@ -48,7 +48,7 @@ impl ConstraintBuilder { } } - pub(crate) fn set_cell_manager(&mut self, cell_manager: CellManager) { + pub(crate) fn set_cell_manager(&mut self, cell_manager: CellManager) { self.cell_manager = Some(cell_manager); } @@ -126,7 +126,7 @@ impl ConstraintBuilder { pub(crate) fn query_byte(&mut self) -> Cell { // TODO(Brecht): fix - self.query_cell_with_type(CellType::Storage) + self.query_cell_with_type(CellType_::StoragePhase1) } pub(crate) fn query_bytes(&mut self) -> [Cell; N] { @@ -134,24 +134,24 @@ impl ConstraintBuilder { } pub(crate) fn query_bytes_dyn(&mut self, count: usize) -> Vec> { - self.query_cells_dyn(CellType::Storage, count) + self.query_cells_dyn(CellType_::StoragePhase1, count) } pub(crate) fn query_cell(&mut self) -> Cell { - self.query_cell_with_type(CellType::Storage) + self.query_cell_with_type(CellType_::StoragePhase1) } pub(crate) fn query_cells(&mut self) -> [Cell; N] { - self.query_cells_dyn(CellType::Storage, N) + self.query_cells_dyn(CellType_::StoragePhase1, N) .try_into() .unwrap() } - pub(crate) fn query_cell_with_type(&mut self, cell_type: CellType) -> Cell { + pub(crate) fn query_cell_with_type(&mut self, cell_type: CellType_) -> Cell { self.query_cells_dyn(cell_type, 1).first().unwrap().clone() } - fn query_cells_dyn(&mut self, cell_type: CellType, count: usize) -> Vec> { + fn query_cells_dyn(&mut self, cell_type: CellType_, count: usize) -> Vec> { self.cell_manager .as_mut() .unwrap() @@ -325,8 +325,8 @@ impl ConstraintBuilder { } } -pub(crate) fn merge_lookups( - cb: &mut ConstraintBuilder, +pub(crate) fn merge_lookups( + cb: &mut ConstraintBuilder, lookups: Vec>, ) -> (Expression, Vec>) { merge_values( @@ -338,8 +338,8 @@ pub(crate) fn merge_lookups( ) } -pub(crate) fn merge_values( - cb: &mut ConstraintBuilder, +pub(crate) fn merge_values( + cb: &mut ConstraintBuilder, values: Vec<(Expression, Vec>)>, ) -> (Expression, Vec>) { let selector = sum::expr(values.iter().map(|(condition, _)| condition.expr())); @@ -689,7 +689,7 @@ macro_rules! _require2 { #[macro_export] macro_rules! _cb { () => {{ - ConstraintBuilder::::new(0, None) + ConstraintBuilder::::new(0, None) }}; } diff --git a/zkevm-circuits/src/circuit_tools/gadgets.rs b/zkevm-circuits/src/circuit_tools/gadgets.rs index b1e21c5c9c..59fcc42266 100644 --- a/zkevm-circuits/src/circuit_tools/gadgets.rs +++ b/zkevm-circuits/src/circuit_tools/gadgets.rs @@ -2,23 +2,23 @@ use eth_types::Field; use gadgets::util::Expr; use halo2_proofs::{ - circuit::Region, + circuit::{Region, Value}, plonk::{Error, Expression}, }; use crate::evm_circuit::util::{from_bytes, pow_of_two}; -use super::{cell_manager::Cell, constraint_builder::ConstraintBuilder}; +use super::{cell_manager::{Cell, CustomTable}, constraint_builder::ConstraintBuilder, cached_region::CachedRegion}; /// Returns `1` when `value == 0`, and returns `0` otherwise. #[derive(Clone, Debug, Default)] pub struct IsZeroGadget { - inverse: Cell, + inverse: Option>, is_zero: Option>, } impl IsZeroGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, value: Expression) -> Self { + pub(crate) fn construct(cb: &mut ConstraintBuilder, value: Expression) -> Self { circuit!([meta, cb], { let inverse = cb.query_cell(); @@ -29,7 +29,7 @@ impl IsZeroGadget { require!(inverse.expr() * is_zero.expr() => 0); Self { - inverse, + inverse: Some(inverse), is_zero: Some(is_zero), } }) @@ -41,12 +41,12 @@ impl IsZeroGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, value: F, ) -> Result { let inverse = value.invert().unwrap_or(F::zero()); - self.inverse.assign(region, offset, inverse)?; + self.inverse.unwrap().assign(region, offset, Value::known(inverse))?; Ok(if value.is_zero().into() { F::one() } else { @@ -62,8 +62,8 @@ pub struct IsEqualGadget { } impl IsEqualGadget { - pub(crate) fn construct( - cb: &mut ConstraintBuilder, + pub(crate) fn construct( + cb: &mut ConstraintBuilder, lhs: Expression, rhs: Expression, ) -> Self { @@ -78,7 +78,7 @@ impl IsEqualGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, lhs: F, rhs: F, @@ -97,7 +97,7 @@ impl IsEqualGadget { /// be `1` when `lhs < rhs`. #[derive(Clone, Debug, Default)] pub struct LtGadget { - lt: Cell, // `1` when `lhs < rhs`, `0` otherwise. + lt: Option>, // `1` when `lhs < rhs`, `0` otherwise. diff: Option<[Cell; N_BYTES]>, /* The byte values of `diff`. * `diff` equals `lhs - rhs` if `lhs >= rhs`, * `lhs - rhs + range` otherwise. */ @@ -105,8 +105,8 @@ pub struct LtGadget { } impl LtGadget { - pub(crate) fn construct( - cb: &mut ConstraintBuilder, + pub(crate) fn construct( + cb: &mut ConstraintBuilder, lhs: Expression, rhs: Expression, ) -> Self { @@ -122,33 +122,33 @@ impl LtGadget { ); Self { - lt, + lt: Some(lt), diff: Some(diff), range, } } pub(crate) fn expr(&self) -> Expression { - self.lt.expr() + self.lt.unwrap().expr() } pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, lhs: F, rhs: F, ) -> Result<(F, Vec), Error> { // Set `lt` let lt = lhs < rhs; - self.lt - .assign(region, offset, if lt { F::one() } else { F::zero() })?; + self.lt.unwrap() + .assign(region, offset, if lt { Value::known(F::one()) } else { Value::known(F::zero()) })?; // Set the bytes of diff let diff = (lhs - rhs) + (if lt { self.range } else { F::zero() }); let diff_bytes = diff.to_repr(); for (idx, diff) in self.diff.as_ref().unwrap().iter().enumerate() { - diff.assign(region, offset, F::from(diff_bytes[idx] as u64))?; + diff.assign(region, offset, Value::known(F::from(diff_bytes[idx] as u64)))?; } Ok((if lt { F::one() } else { F::zero() }, diff_bytes.to_vec())) diff --git a/zkevm-circuits/src/circuit_tools/memory.rs b/zkevm-circuits/src/circuit_tools/memory.rs index 9eeeca1d51..a9a6910609 100644 --- a/zkevm-circuits/src/circuit_tools/memory.rs +++ b/zkevm-circuits/src/circuit_tools/memory.rs @@ -11,7 +11,7 @@ use std::{ ops::{Index, IndexMut}, }; -use super::constraint_builder::ConstraintBuilder; +use super::{constraint_builder::ConstraintBuilder, cell_manager::CustomTable}; #[derive(Clone, Debug, Default)] pub(crate) struct Memory { @@ -55,9 +55,9 @@ impl Memory { unreachable!() } - pub(crate) fn generate_constraints( + pub(crate) fn generate_constraints( &self, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, is_first_row: Expression, ) { for bank in self.banks.iter() { @@ -150,29 +150,29 @@ impl MemoryBank { self.cur.expr() } - pub(crate) fn load( + pub(crate) fn load( &self, description: &'static str, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, offset: Expression, values: &[Expression], ) { self.load_with_key(description, cb, self.key() - offset, values); } - pub(crate) fn load_with_key( + pub(crate) fn load_with_key( &self, description: &'static str, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, key: Expression, values: &[Expression], ) { cb.lookup(description, self.tag(), self.insert_key(key, values)); } - pub(crate) fn store( + pub(crate) fn store( &self, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, values: &[Expression], ) -> Expression { let key = self.key() + 1.expr(); @@ -180,9 +180,9 @@ impl MemoryBank { key } - pub(crate) fn store_with_key( + pub(crate) fn store_with_key( &self, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, key: Expression, values: &[Expression], ) { @@ -202,9 +202,9 @@ impl MemoryBank { self.store_offsets.clear(); } - pub(crate) fn generate_constraints( + pub(crate) fn generate_constraints( &self, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, is_first_row: Expression, ) { let lookup_table = cb.get_lookup_table(self.tag()); @@ -251,7 +251,7 @@ impl MemoryBank { self.tag.clone() } - pub(crate) fn insert_key(&self, key: T, values: &[T]) -> Vec { + pub(crate) fn insert_key(&self, key: V, values: &[V]) -> Vec { [vec![key], values.to_owned()].concat().to_vec() } } diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 1d29c97722..3df6ea318b 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -194,7 +194,7 @@ impl<'r, 'b, F: Field> CachedRegion<'r, 'b, F> { pub fn word_rlc(&self, n: U256) -> Value { self.challenges .evm_word() - .map(|r| rlc::value(&n.to_le_bytes(), r)) + .map(|r: F| rlc::value(&n.to_le_bytes(), r)) } pub fn empty_code_hash_rlc(&self) -> Value { self.word_rlc(CodeDB::empty_code_hash().to_word()) diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 8f1fff1ab1..5095e4d778 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -22,11 +22,13 @@ mod rlp_gadgets; mod start; mod storage_leaf; mod witness_row; +mod table; use self::{ account_leaf::AccountLeafConfig, helpers::{key_memory, RLPItemView}, witness_row::{StartRowType,ExtensionBranchRowType, AccountRowType, StorageRowType,Node}, + table::Table, }; use crate::{ assign, assignf, circuit, @@ -38,6 +40,7 @@ use crate::{ start::StartConfig, storage_leaf::StorageLeafConfig, }, + evm_circuit::util::CachedRegion, table::{KeccakTable, LookupTable, MPTProofType, MptTable}, util::Challenges, }; @@ -98,7 +101,7 @@ impl MPTContext { pub(crate) fn rlp_item( &self, meta: &mut VirtualCells, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, idx: usize, ) -> RLPItemView { // TODO(Brecht): Add RLP limitations like max num bytes @@ -108,7 +111,7 @@ impl MPTContext { pub(crate) fn nibbles( &self, meta: &mut VirtualCells, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, idx: usize, ) -> RLPItemView { self.rlp_item.create_view(meta, cb, idx, true) @@ -367,6 +370,7 @@ impl MPTConfig { if node.start.is_some() { // println!("{}: start", offset); assign!(region, (self.state_machine.is_start, offset) => true.scalar())?; + self.state_machine.start_config.assign( &mut region, self, @@ -629,6 +633,7 @@ mod tests { }); } + #[cfg(feature = "dev-graph")] #[test] fn graph_mpt() { use plotters::prelude::*; diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index c16f0b4ee1..cbb1f088a5 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -1,7 +1,7 @@ use crate::{ assign, circuit, circuit_tools::{ - cell_manager::{Cell, CellManager}, + cell_manager::{Cell, CellManager, CustomTable}, constraint_builder::{ ConstraintBuilder, RLCChainable, RLCChainableValue, RLCable, RLCableValue, }, @@ -26,6 +26,7 @@ use super::{ rlp_gadgets::{ get_ext_odd_nibble_value, RLPItemGadget, RLPItemWitness, RLPListGadget, RLPListWitness, }, + table::Table, FixedTableTag, }; @@ -56,7 +57,7 @@ pub(crate) struct LeafKeyWitness { } impl LeafKeyGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, rlp_key: RLPItemView) -> Self { + pub(crate) fn construct(cb: &mut ConstraintBuilder, rlp_key: RLPItemView) -> Self { circuit!([meta, cb], { let has_no_nibbles = IsEqualGadget::::construct( cb, @@ -69,14 +70,14 @@ impl LeafKeyGadget { pub(crate) fn expr( &self, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, rlp_key: RLPItemView, key_mult_prev: Expression, is_key_odd: Expression, r: &Expression, ) -> Expression { circuit!([meta, cb], { - let calc_rlc = |cb: &mut ConstraintBuilder, + let calc_rlc = |cb: &mut ConstraintBuilder, bytes: &[Expression], is_key_odd: Expression| { leaf_key_rlc(cb, bytes, key_mult_prev.expr(), is_key_odd.expr(), r) @@ -142,8 +143,8 @@ impl LeafKeyWitness { } } -pub(crate) fn ext_key_rlc_expr( - cb: &mut ConstraintBuilder, +pub(crate) fn ext_key_rlc_expr( + cb: &mut ConstraintBuilder, key_value: RLPItemView, key_mult_prev: Expression, is_key_part_odd: Expression, @@ -154,7 +155,7 @@ pub(crate) fn ext_key_rlc_expr( circuit!([meta, cb], { let (is_short, is_long) = (key_value.is_short(), key_value.is_long()); let mult_first_odd = ifx! {is_key_odd => { 1.expr() } elsex { 16.expr() }}; - let calc_rlc = |cb: &mut ConstraintBuilder, + let calc_rlc = |cb: &mut ConstraintBuilder, bytes: &[Expression], key_mult_first_even: Expression| { ext_key_rlc( @@ -256,7 +257,7 @@ pub(crate) struct ListKeyWitness { } impl ListKeyGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, key_value: &RLPItemView) -> Self { + pub(crate) fn construct(cb: &mut ConstraintBuilder, key_value: &RLPItemView) -> Self { let rlp_list_bytes = cb.query_bytes(); let rlp_list_bytes_expr = rlp_list_bytes.iter().map(|c| c.expr()).collect::>(); let key = LeafKeyGadget::construct(cb, key_value.clone()); @@ -330,7 +331,7 @@ pub(crate) struct KeyDataWitness { impl KeyData { pub(crate) fn load( - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, memory: &MemoryBank, offset: Expression, ) -> Self { @@ -365,7 +366,7 @@ impl KeyData { } pub(crate) fn store( - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, memory: &MemoryBank, rlc: Expression, mult: Expression, @@ -391,7 +392,7 @@ impl KeyData { ); } - pub(crate) fn store_defaults(cb: &mut ConstraintBuilder, memory: &MemoryBank) { + pub(crate) fn store_defaults(cb: &mut ConstraintBuilder, memory: &MemoryBank) { memory.store(cb, &KeyData::default_values_expr()); } @@ -484,7 +485,7 @@ pub(crate) struct ParentDataWitness { impl ParentData { pub(crate) fn load( description: &'static str, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, memory: &MemoryBank, offset: Expression, ) -> Self { @@ -511,7 +512,7 @@ impl ParentData { } pub(crate) fn store( - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, memory: &MemoryBank, rlc: Expression, is_root: Expression, @@ -586,7 +587,7 @@ pub(crate) struct MainDataWitness { impl MainData { pub(crate) fn load( description: &'static str, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, memory: &MemoryBank, offset: Expression, ) -> Self { @@ -615,7 +616,7 @@ impl MainData { } pub(crate) fn store( - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, memory: &MemoryBank, values: [Expression; 5], ) { @@ -670,8 +671,8 @@ impl MainData { } /// Add the nibble from the drifted branch -pub(crate) fn nibble_rlc( - cb: &mut ConstraintBuilder, +pub(crate) fn nibble_rlc( + cb: &mut ConstraintBuilder, key_rlc: Expression, key_mult_prev: Expression, is_key_odd: Expression, @@ -693,8 +694,8 @@ pub(crate) fn nibble_rlc( }) } -pub(crate) fn leaf_key_rlc( - cb: &mut ConstraintBuilder, +pub(crate) fn leaf_key_rlc( + cb: &mut ConstraintBuilder, bytes: &[Expression], key_mult_prev: Expression, is_key_odd: Expression, @@ -712,8 +713,8 @@ pub(crate) fn leaf_key_rlc( }) } -pub(crate) fn ext_key_rlc( - cb: &mut ConstraintBuilder, +pub(crate) fn ext_key_rlc( + cb: &mut ConstraintBuilder, bytes: &[Expression], key_mult_prev: Expression, is_odd: Expression, @@ -757,11 +758,11 @@ pub(crate) fn ext_key_rlc_value( // Returns the number of nibbles stored in a key value pub(crate) mod num_nibbles { - use crate::{_cb, circuit, circuit_tools::constraint_builder::ConstraintBuilder}; + use crate::{_cb, circuit, circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::CustomTable}}; use eth_types::Field; use halo2_proofs::plonk::Expression; - pub(crate) fn expr( + pub(crate) fn expr( key_len: Expression, is_key_odd: Expression, ) -> Expression { @@ -797,11 +798,11 @@ pub(crate) fn main_memory() -> String { /// MPTConstraintBuilder #[derive(Clone)] pub struct MPTConstraintBuilder { - pub base: ConstraintBuilder, + pub base: ConstraintBuilder, } impl MPTConstraintBuilder { - pub(crate) fn new(max_degree: usize, cell_manager: Option>) -> Self { + pub(crate) fn new(max_degree: usize, cell_manager: Option>) -> Self { MPTConstraintBuilder { base: ConstraintBuilder::new(max_degree, cell_manager), } @@ -817,7 +818,7 @@ pub struct IsEmptyTreeGadget { impl IsEmptyTreeGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, parent_rlc: Expression, r: &Expression, ) -> Self { @@ -1116,7 +1117,7 @@ impl MainRLPGadget { pub(crate) fn create_view( &self, meta: &mut VirtualCells, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, rot: usize, is_nibbles: bool, ) -> RLPItemView { diff --git a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs index a289de9968..f188ae0ad6 100644 --- a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs +++ b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs @@ -1,11 +1,12 @@ use crate::{ _cb, circuit, circuit_tools::{ - cell_manager::Cell, + cell_manager::{Cell, CustomTable}, constraint_builder::{ConstraintBuilder, RLCable, RLCableValue}, }, matchw, mpt_circuit::param::{RLP_LIST_LONG, RLP_LIST_SHORT, RLP_SHORT}, + mpt_circuit::table::Table, util::Expr, }; use eth_types::Field; @@ -36,7 +37,7 @@ pub(crate) struct RLPListWitness { } impl RLPListGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, bytes: &[Expression]) -> Self { + pub(crate) fn construct(cb: &mut ConstraintBuilder, bytes: &[Expression]) -> Self { // TODO(Brecht): add lookup RLPListGadget { is_short: cb.query_cell(), @@ -103,7 +104,7 @@ impl RLPListGadget { } /// Number of RLP bytes - pub(crate) fn num_rlp_bytes(&self) -> Expression { + pub(crate) fn num_rlp_bytes(&self) -> Expression { circuit!([meta, _cb!()], { matchx! { self.is_short() => 1.expr(), @@ -119,7 +120,7 @@ impl RLPListGadget { } /// Returns the length of the list (excluding RLP bytes) - pub(crate) fn len(&self) -> Expression { + pub(crate) fn len(&self) -> Expression { circuit!([meta, _cb!()], { matchx! { self.is_short() => get_len_list_short::expr(self.bytes[0].expr()), @@ -135,7 +136,7 @@ impl RLPListGadget { } /// Returns the rlc of only the RLP bytes - pub(crate) fn rlc_rlp_only(&self, r: &Expression) -> (Expression, Expression) { + pub(crate) fn rlc_rlp_only(&self, r: &Expression) -> (Expression, Expression) { circuit!([meta, _cb!()], { matchx! { self.is_short() => (self.bytes[..1].rlc(r), pow::expr(r.expr(), 1)), @@ -219,7 +220,7 @@ pub(crate) struct RLPListDataGadget { } impl RLPListDataGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder) -> Self { + pub(crate) fn construct(cb: &mut ConstraintBuilder) -> Self { let rlp_list_bytes = cb.query_bytes(); let rlp_list_bytes_expr = rlp_list_bytes.iter().map(|c| c.expr()).collect::>(); RLPListDataGadget { @@ -264,7 +265,7 @@ pub(crate) struct RLPValueWitness { } impl RLPValueGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, bytes: &[Expression]) -> Self { + pub(crate) fn construct(cb: &mut ConstraintBuilder, bytes: &[Expression]) -> Self { // TODO(Brecht): add lookup RLPValueGadget { is_short: cb.query_cell(), @@ -333,7 +334,7 @@ impl RLPValueGadget { } /// Number of RLP bytes - pub(crate) fn num_rlp_bytes(&self) -> Expression { + pub(crate) fn num_rlp_bytes(&self) -> Expression { circuit!([meta, _cb!()], { matchx! { self.is_short() => 0.expr(), @@ -344,7 +345,7 @@ impl RLPValueGadget { } /// Number of bytes in total (including RLP bytes) - pub(crate) fn num_bytes(&self) -> Expression { + pub(crate) fn num_bytes(&self) -> Expression { circuit!([meta, _cb!()], { matchx! { self.is_short() => 1.expr(), @@ -358,7 +359,7 @@ impl RLPValueGadget { } /// Length of the value (excluding RLP bytes) - pub(crate) fn len(&self) -> Expression { + pub(crate) fn len(&self) -> Expression { circuit!([meta, _cb!()], { matchx! { self.is_short() => 1.expr(), @@ -372,7 +373,7 @@ impl RLPValueGadget { } /// RLC data - pub(crate) fn rlc(&self, r: &Expression) -> (Expression, Expression) { + pub(crate) fn rlc(&self, r: &Expression) -> (Expression, Expression) { (self.rlc_value(r), self.rlc_rlp(r)) } @@ -380,7 +381,7 @@ impl RLPValueGadget { self.bytes.rlc(r) } - pub(crate) fn rlc_value(&self, r: &Expression) -> Expression { + pub(crate) fn rlc_value(&self, r: &Expression) -> Expression { circuit!([meta, _cb!()], { matchx! { self.is_short() => { @@ -558,7 +559,7 @@ pub(crate) struct RLPItemWitness { } impl RLPItemGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, bytes: &[Expression]) -> Self { + pub(crate) fn construct(cb: &mut ConstraintBuilder, bytes: &[Expression]) -> Self { RLPItemGadget { value: RLPValueGadget::construct(cb, bytes), list: RLPListGadget::construct(cb, bytes), @@ -583,7 +584,7 @@ impl RLPItemGadget { } // Single RLP byte containing the byte value - pub(crate) fn is_short(&self) -> Expression { + pub(crate) fn is_short(&self) -> Expression { circuit!([meta, _cb!()], { matchx! { self.value.is_string() => self.value.is_short(), @@ -593,7 +594,7 @@ impl RLPItemGadget { } // Single RLP byte containing the length of the value - pub(crate) fn is_long(&self) -> Expression { + pub(crate) fn is_long(&self) -> Expression { circuit!([meta, _cb!()], { matchx! { self.value.is_string() => self.value.is_long(), @@ -604,7 +605,7 @@ impl RLPItemGadget { // RLP byte containing the lenght of the length, // followed by the length, followed by the actual data - pub(crate) fn is_very_long(&self) -> Expression { + pub(crate) fn is_very_long(&self) -> Expression { circuit!([meta, _cb!()], { matchx! { self.value.is_string() => self.value.is_very_long(), @@ -614,38 +615,38 @@ impl RLPItemGadget { } /// Number of RLP bytes - pub(crate) fn num_rlp_bytes(&self) -> Expression { + pub(crate) fn num_rlp_bytes(&self) -> Expression { circuit!([meta, _cb!()], { matchx! { - self.value.is_string() => self.value.num_rlp_bytes(), - self.list.is_list() => self.list.num_rlp_bytes(), + self.value.is_string() => self.value.num_rlp_bytes::(), + self.list.is_list() => self.list.num_rlp_bytes::(), } }) } /// Number of bytes in total (including RLP bytes) - pub(crate) fn num_bytes(&self) -> Expression { + pub(crate) fn num_bytes(&self) -> Expression { circuit!([meta, _cb!()], { matchx! { - self.value.is_string() => self.value.num_bytes(), + self.value.is_string() => self.value.num_bytes::(), self.list.is_list() => self.list.num_bytes(), } }) } /// Length of the value (excluding RLP bytes) - pub(crate) fn len(&self) -> Expression { + pub(crate) fn len(&self) -> Expression { circuit!([meta, _cb!()], { matchx! { - self.value.is_string() => self.value.len(), - self.list.is_list() => self.list.len(), + self.value.is_string() => self.value.len::(), + self.list.is_list() => self.list.len::(), } }) } - pub(crate) fn rlc_rlp( + pub(crate) fn rlc_rlp( &self, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, r: &Expression, ) -> Expression { circuit!([meta, cb], { @@ -658,10 +659,10 @@ impl RLPItemGadget { // Returns the RLC of the value if the RLP is a string, // returns the RLC of the full string if the RLP is a list. - pub(crate) fn rlc_content(&self, r: &Expression) -> Expression { + pub(crate) fn rlc_content(&self, r: &Expression) -> Expression { circuit!([meta, _cb!()], { matchx! { - self.value.is_string() => self.value.rlc_value(r), + self.value.is_string() => self.value.rlc_value::(r), self.list.is_list() => self.list.rlc_rlp(r), } }) diff --git a/zkevm-circuits/src/mpt_circuit/table.rs b/zkevm-circuits/src/mpt_circuit/table.rs new file mode 100644 index 0000000000..6add9a7221 --- /dev/null +++ b/zkevm-circuits/src/mpt_circuit/table.rs @@ -0,0 +1,21 @@ + +use strum_macros::EnumIter; +use crate::circuit_tools::cell_manager::CustomTable; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] +pub(crate) enum Table { + Fixed, + Tx, + Rw, + Bytecode, + Block, + Copy, + Keccak, + Exp, +} + +impl CustomTable for Table { + fn matches_to(&self, other: &Self) -> bool { + self == other + } +} \ No newline at end of file diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 3431d1e8c8..90f8b05887 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -2,7 +2,7 @@ use crate::{ circuit, - circuit_tools::constraint_builder::ConstraintBuilder, + circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::CustomTable}, copy_circuit::number_or_hash_to_field, evm_circuit::util::rlc, exp_circuit::{OFFSET_INCREMENT, ROWS_PER_STEP}, @@ -657,10 +657,10 @@ impl MptTable { } } - pub(crate) fn constrain( + pub(crate) fn constrain( &self, meta: &mut VirtualCells<'_, F>, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, address_rlc: Expression, proof_type: Expression, key_rlc: Expression, From 16f4e16b4419bdf43e252d0cb220049b9d983dc0 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Thu, 4 May 2023 00:56:03 +0800 Subject: [PATCH 023/102] use new circuit tools including CachecdRegion --- .../src/circuit_tools/cached_region.rs | 24 ++++- .../src/circuit_tools/cell_manager.rs | 51 +++++++--- zkevm-circuits/src/circuit_tools/gadgets.rs | 6 +- zkevm-circuits/src/mpt_circuit.rs | 58 ++++++++--- .../src/mpt_circuit/account_leaf.rs | 6 +- zkevm-circuits/src/mpt_circuit/branch.rs | 4 +- zkevm-circuits/src/mpt_circuit/extension.rs | 4 +- .../src/mpt_circuit/extension_branch.rs | 4 +- zkevm-circuits/src/mpt_circuit/helpers.rs | 44 ++++----- zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs | 99 +++++++++++-------- zkevm-circuits/src/mpt_circuit/start.rs | 9 +- .../src/mpt_circuit/storage_leaf.rs | 6 +- 12 files changed, 206 insertions(+), 109 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools/cached_region.rs b/zkevm-circuits/src/circuit_tools/cached_region.rs index c1bb827d87..b2205a1173 100644 --- a/zkevm-circuits/src/circuit_tools/cached_region.rs +++ b/zkevm-circuits/src/circuit_tools/cached_region.rs @@ -6,7 +6,7 @@ use bus_mapping::state_db::CodeDB; use eth_types::{Field, ToLittleEndian, ToWord, U256}; use halo2_proofs::{ circuit::{AssignedCell, Region, Value}, - plonk::{Advice, Assigned, Column, Error, Expression}, + plonk::{Advice, Assigned, Column, Error, Expression, Fixed}, poly::Rotation, }; use itertools::Itertools; @@ -106,6 +106,22 @@ impl<'r, 'b, F: Field> CachedRegion<'r, 'b, F> { res } + pub fn assign_fixed<'v, V, VR, A, AR>( + &'v mut self, + annotation: A, + column: Column, + offset: usize, + to: V, + ) -> Result, Error> + where + V: Fn() -> Value + 'v, + for<'vr> Assigned: From<&'vr VR>, + A: Fn() -> AR, + AR: Into, + { + self.region.assign_fixed(annotation, column, offset, &to) + } + pub fn get_fixed(&self, _row_index: usize, _column_index: usize, _rotation: Rotation) -> F { unimplemented!("fixed column"); } @@ -115,6 +131,10 @@ impl<'r, 'b, F: Field> CachedRegion<'r, 'b, F> { [(((row_index - self.height_start) as i32) + rotation.0) as usize] } + pub fn region(&mut self) -> &mut Region<'_, F> { + self.region + } + pub fn challenges(&self) -> &Challenges> { self.challenges } @@ -190,7 +210,7 @@ impl StoredExpression { &|a, b| a * b, &|a, scalar| a * Value::known(scalar), ); - self.cell.assign(region, offset, value)?; + self.cell.assign_value(region, offset, value)?; Ok(value) } } diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index 563faa7e64..bbea1ea754 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -14,11 +14,11 @@ use std::fmt::Debug; use std::hash::Hash; use strum_macros::EnumIter; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub(crate) struct Cell { // expression for constraint - expression: Expression, - column: Column, + expression: Option>, + column: Option>, // relative position to selector for synthesis rotation: usize, cell_column_index: usize, @@ -33,8 +33,8 @@ impl Cell { cell_column_index: usize, ) -> Self { Self { - expression: meta.query_advice(column, Rotation(rotation as i32)), - column, + expression: Some(meta.query_advice(column, Rotation(rotation as i32))), + column: Some(column), rotation, cell_column_index, } @@ -45,7 +45,7 @@ impl Cell { &self, region: &mut CachedRegion<'_, '_, F>, offset: usize, - value: Value, + value: F, ) -> Result, Error> { region.assign_advice( || { @@ -54,14 +54,33 @@ impl Cell { self.column, self.rotation ) }, - self.column, + self.column.unwrap(), + offset + self.rotation, + || Value::known(value), + ) + } + + pub(crate) fn assign_value( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + value: Value, + ) -> Result, Error> { + region.assign_advice( + || { + format!( + "Cell column: {:?} and rotation: {}", + self.column.unwrap(), self.rotation + ) + }, + self.column.unwrap(), offset + self.rotation, || value, ) } pub(crate) fn column(&self) -> Column { - self.column + self.column.unwrap() } pub(crate) fn rotation(&self) -> usize { @@ -69,19 +88,19 @@ impl Cell { } pub(crate) fn rot(&self, meta: &mut VirtualCells, rot: usize) -> Expression { - meta.query_advice(self.column, Rotation((self.rotation + rot) as i32)) + meta.query_advice(self.column.unwrap(), Rotation((self.rotation + rot) as i32)) } } impl Expr for Cell { fn expr(&self) -> Expression { - self.expression.clone() + self.expression.unwrap().clone() } } impl Expr for &Cell { fn expr(&self) -> Expression { - self.expression.clone() + self.expression.unwrap().clone() } } @@ -103,7 +122,7 @@ pub(crate) enum CellType_ { Lookup(T), } -pub trait CustomTable: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash { +pub trait CustomTable: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash{ fn matches_to(&self, other: &Self) -> bool; } @@ -282,6 +301,14 @@ impl CellManager { self.query_cells(cell_type, 1)[0].clone() } + pub(crate) fn reset(&mut self, height: usize) { + assert!(height <= self.height); + self.height = height; + for column in self.columns.iter_mut() { + column.height = 0; + } + } + fn next_column(&self, cell_type: CellType_) -> usize { let mut best_index: Option = None; let mut best_height = self.height; diff --git a/zkevm-circuits/src/circuit_tools/gadgets.rs b/zkevm-circuits/src/circuit_tools/gadgets.rs index 59fcc42266..154e5b6b2d 100644 --- a/zkevm-circuits/src/circuit_tools/gadgets.rs +++ b/zkevm-circuits/src/circuit_tools/gadgets.rs @@ -46,7 +46,7 @@ impl IsZeroGadget { value: F, ) -> Result { let inverse = value.invert().unwrap_or(F::zero()); - self.inverse.unwrap().assign(region, offset, Value::known(inverse))?; + self.inverse.unwrap().assign(region, offset, inverse)?; Ok(if value.is_zero().into() { F::one() } else { @@ -142,13 +142,13 @@ impl LtGadget { // Set `lt` let lt = lhs < rhs; self.lt.unwrap() - .assign(region, offset, if lt { Value::known(F::one()) } else { Value::known(F::zero()) })?; + .assign(region, offset, if lt { F::one() } else { F::zero() })?; // Set the bytes of diff let diff = (lhs - rhs) + (if lt { self.range } else { F::zero() }); let diff_bytes = diff.to_repr(); for (idx, diff) in self.diff.as_ref().unwrap().iter().enumerate() { - diff.assign(region, offset, Value::known(F::from(diff_bytes[idx] as u64)))?; + diff.assign(region, offset, F::from(diff_bytes[idx] as u64))?; } Ok((if lt { F::one() } else { F::zero() }, diff_bytes.to_vec())) diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 5095e4d778..2164ea0a42 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -34,13 +34,13 @@ use crate::{ assign, assignf, circuit, circuit_tools::{ cell_manager::CellManager, constraint_builder::ConstraintBuilder, memory::Memory, + cached_region::CachedRegion, }, mpt_circuit::{ helpers::{main_memory, parent_memory, MPTConstraintBuilder, MainRLPGadget}, start::StartConfig, storage_leaf::StorageLeafConfig, }, - evm_circuit::util::CachedRegion, table::{KeccakTable, LookupTable, MPTProofType, MptTable}, util::Challenges, }; @@ -352,27 +352,40 @@ impl MPTConfig { for node in nodes.iter() { // Assign bytes let mut rlp_values = Vec::new(); + let mut cahced_region = CachedRegion::new( + &mut region, + challenges, + self.managed_columns.clone(), + node.values.len(), + offset + ); for (idx, bytes) in node.values.iter().enumerate() { let is_nibbles = node.extension_branch.is_some() && idx == ExtensionBranchRowType::KeyC as usize; let rlp_value = self.rlp_item.assign( - &mut region, + &mut cahced_region, offset + idx, bytes, r, is_nibbles, )?; rlp_values.push(rlp_value); - assignf!(region, (self.rows_left_in_state, offset + idx) => (node.values.len() - idx).scalar())?; + assignf!(cahced_region, (self.rows_left_in_state, offset + idx) => (node.values.len() - idx).scalar())?; } // Assign nodes if node.start.is_some() { // println!("{}: start", offset); - assign!(region, (self.state_machine.is_start, offset) => true.scalar())?; - - self.state_machine.start_config.assign( + let mut cahced_region = CachedRegion::new( &mut region, + challenges, + self.managed_columns.clone(), + StartRowType::Count as usize, + offset + ); + assign!(cahced_region, (self.state_machine.is_start, offset) => true.scalar())?; + self.state_machine.start_config.assign( + &mut cahced_region, self, &mut pv, offset, @@ -381,9 +394,16 @@ impl MPTConfig { )?; } else if node.extension_branch.is_some() { // println!("{}: branch", offset); - assign!(region, (self.state_machine.is_branch, offset) => true.scalar())?; - self.state_machine.branch_config.assign( + let mut cahced_region = CachedRegion::new( &mut region, + challenges, + self.managed_columns.clone(), + ExtensionBranchRowType::Count as usize, + offset + ); + assign!(cahced_region, (self.state_machine.is_branch, offset) => true.scalar())?; + self.state_machine.branch_config.assign( + &mut cahced_region, self, &mut pv, offset, @@ -392,9 +412,16 @@ impl MPTConfig { )?; } else if node.storage.is_some() { // println!("{}: storage", offset); - assign!(region, (self.state_machine.is_storage, offset) => true.scalar())?; - self.state_machine.storage_config.assign( + let mut cahced_region = CachedRegion::new( &mut region, + challenges, + self.managed_columns.clone(), + StorageRowType::Count as usize, + offset + ); + assign!(cahced_region, (self.state_machine.is_storage, offset) => true.scalar())?; + self.state_machine.storage_config.assign( + &mut cahced_region, self, &mut pv, offset, @@ -403,9 +430,16 @@ impl MPTConfig { )?; } else if node.account.is_some() { // println!("{}: account", offset); - assign!(region, (self.state_machine.is_account, offset) => true.scalar())?; - self.state_machine.account_config.assign( + let mut cahced_region = CachedRegion::new( &mut region, + challenges, + self.managed_columns.clone(), + AccountRowType::Count as usize, + offset + ); + assign!(cahced_region, (self.state_machine.is_account, offset) => true.scalar())?; + self.state_machine.account_config.assign( + &mut cahced_region, self, &mut pv, offset, diff --git a/zkevm-circuits/src/mpt_circuit/account_leaf.rs b/zkevm-circuits/src/mpt_circuit/account_leaf.rs index 9916e307a8..2a5a0996dd 100644 --- a/zkevm-circuits/src/mpt_circuit/account_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/account_leaf.rs @@ -17,7 +17,7 @@ use crate::{ circuit_tools::{ cell_manager::Cell, constraint_builder::{RLCChainable, RLCable, RLCableValue}, - gadgets::IsEqualGadget, + gadgets::IsEqualGadget, cached_region::CachedRegion, }, mpt_circuit::{ helpers::{ @@ -359,7 +359,7 @@ impl AccountLeafConfig { pub fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, ctx: &MPTConfig, pv: &mut MPTState, offset: usize, @@ -572,7 +572,7 @@ impl AccountLeafConfig { (MPTProofType::Disabled, vec![0.scalar(); 2]) }; ctx.mpt_table.assign( - region, + region.region(), offset, &MptUpdateRow { address_rlc: Value::known(account.address.rlc_value(pv.r)), diff --git a/zkevm-circuits/src/mpt_circuit/branch.rs b/zkevm-circuits/src/mpt_circuit/branch.rs index 433b390e1d..3afc687372 100644 --- a/zkevm-circuits/src/mpt_circuit/branch.rs +++ b/zkevm-circuits/src/mpt_circuit/branch.rs @@ -14,7 +14,7 @@ use super::{ }; use crate::{ circuit, - circuit_tools::{cell_manager::Cell, constraint_builder::RLCChainable, gadgets::LtGadget}, + circuit_tools::{cell_manager::Cell, constraint_builder::RLCChainable, gadgets::LtGadget, cached_region::CachedRegion}, mpt_circuit::{ helpers::{nibble_rlc, Indexable}, param::{HASH_WIDTH, RLP_NIL}, @@ -272,7 +272,7 @@ impl BranchGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/extension.rs b/zkevm-circuits/src/mpt_circuit/extension.rs index 47c38202dd..4656b26df3 100644 --- a/zkevm-circuits/src/mpt_circuit/extension.rs +++ b/zkevm-circuits/src/mpt_circuit/extension.rs @@ -13,7 +13,7 @@ use super::{ }; use crate::{ circuit, - circuit_tools::{cell_manager::Cell, constraint_builder::RLCChainable, gadgets::LtGadget}, + circuit_tools::{cell_manager::Cell, constraint_builder::RLCChainable, gadgets::LtGadget, cached_region::CachedRegion}, mpt_circuit::{ helpers::{ ext_key_rlc_calc_value, ext_key_rlc_expr, num_nibbles, Indexable, KeyData, ParentData, @@ -181,7 +181,7 @@ impl ExtensionGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/extension_branch.rs b/zkevm-circuits/src/mpt_circuit/extension_branch.rs index 03623c3696..669f137c03 100644 --- a/zkevm-circuits/src/mpt_circuit/extension_branch.rs +++ b/zkevm-circuits/src/mpt_circuit/extension_branch.rs @@ -15,7 +15,7 @@ use super::{ }; use crate::{ circuit, - circuit_tools::cell_manager::Cell, + circuit_tools::{cell_manager::Cell, cached_region::CachedRegion}, mpt_circuit::{ helpers::{key_memory, parent_memory, Indexable, KeyData, ParentData}, witness_row::ExtensionBranchRowType, @@ -184,7 +184,7 @@ impl ExtensionBranchConfig { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index cbb1f088a5..701841f4ea 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -6,7 +6,7 @@ use crate::{ ConstraintBuilder, RLCChainable, RLCChainableValue, RLCable, RLCableValue, }, gadgets::IsEqualGadget, - memory::MemoryBank, + memory::MemoryBank, cached_region::CachedRegion, }, matchw, mpt_circuit::{ @@ -18,8 +18,7 @@ use crate::{ use eth_types::Field; use gadgets::util::{or, pow, Scalar}; use halo2_proofs::{ - circuit::Region, - plonk::{Error, Expression, VirtualCells}, + plonk::{Error, Expression, VirtualCells}, circuit::Value, }; use super::{ @@ -99,7 +98,7 @@ impl LeafKeyGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, bytes: &[u8], ) -> Result { @@ -143,7 +142,7 @@ impl LeafKeyWitness { } } -pub(crate) fn ext_key_rlc_expr( +pub(crate) fn ext_key_rlc_expr( cb: &mut ConstraintBuilder, key_value: RLPItemView, key_mult_prev: Expression, @@ -271,7 +270,7 @@ impl ListKeyGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, list_bytes: &[u8], key_item: &RLPItemWitness, @@ -410,7 +409,7 @@ impl KeyData { } pub(crate) fn witness_store( - _region: &mut Region<'_, F>, + _region: &mut CachedRegion<'_, '_, F>, offset: usize, memory: &mut MemoryBank, rlc: F, @@ -437,7 +436,7 @@ impl KeyData { pub(crate) fn witness_load( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, memory: &MemoryBank, load_offset: usize, @@ -523,7 +522,7 @@ impl ParentData { } pub(crate) fn witness_store( - _region: &mut Region<'_, F>, + _region: &mut CachedRegion<'_, '_, F>, offset: usize, memory: &mut MemoryBank, rlc: F, @@ -545,7 +544,7 @@ impl ParentData { pub(crate) fn witness_load( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, memory: &MemoryBank, load_offset: usize, @@ -624,7 +623,7 @@ impl MainData { } pub(crate) fn witness_store( - _region: &mut Region<'_, F>, + _region: &mut CachedRegion<'_, '_, F>, offset: usize, memory: &mut MemoryBank, proof_type: usize, @@ -647,7 +646,7 @@ impl MainData { pub(crate) fn witness_load( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, memory: &MemoryBank, load_offset: usize, @@ -671,7 +670,7 @@ impl MainData { } /// Add the nibble from the drifted branch -pub(crate) fn nibble_rlc( +pub(crate) fn nibble_rlc( cb: &mut ConstraintBuilder, key_rlc: Expression, key_mult_prev: Expression, @@ -694,7 +693,7 @@ pub(crate) fn nibble_rlc( }) } -pub(crate) fn leaf_key_rlc( +pub(crate) fn leaf_key_rlc( cb: &mut ConstraintBuilder, bytes: &[Expression], key_mult_prev: Expression, @@ -713,7 +712,7 @@ pub(crate) fn leaf_key_rlc( }) } -pub(crate) fn ext_key_rlc( +pub(crate) fn ext_key_rlc( cb: &mut ConstraintBuilder, bytes: &[Expression], key_mult_prev: Expression, @@ -758,15 +757,16 @@ pub(crate) fn ext_key_rlc_value( // Returns the number of nibbles stored in a key value pub(crate) mod num_nibbles { - use crate::{_cb, circuit, circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::CustomTable}}; + use crate::{_cb, circuit, circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::CustomTable}, mpt_circuit::table::Table}; use eth_types::Field; use halo2_proofs::plonk::Expression; - pub(crate) fn expr( + pub(crate) fn expr( key_len: Expression, is_key_odd: Expression, ) -> Expression { - circuit!([meta, _cb!()], { + let mut cb = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { ifx! {is_key_odd => { key_len.expr() * 2.expr() - 1.expr() } elsex { @@ -845,7 +845,7 @@ impl IsEmptyTreeGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, parent_rlc: F, r: F, @@ -922,7 +922,7 @@ impl DriftedGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, parent_data: &[ParentDataWitness], drifted_list_bytes: &[u8], @@ -990,7 +990,7 @@ impl WrongGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, is_non_existing: bool, key_rlc: &[F], @@ -1081,7 +1081,7 @@ impl MainRLPGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, bytes: &[u8], r: F, diff --git a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs index f188ae0ad6..5b0ecef57a 100644 --- a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs +++ b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs @@ -1,8 +1,10 @@ +use std::marker::PhantomData; + use crate::{ _cb, circuit, circuit_tools::{ cell_manager::{Cell, CustomTable}, - constraint_builder::{ConstraintBuilder, RLCable, RLCableValue}, + constraint_builder::{ConstraintBuilder, RLCable, RLCableValue}, cached_region::CachedRegion, }, matchw, mpt_circuit::param::{RLP_LIST_LONG, RLP_LIST_SHORT, RLP_SHORT}, @@ -12,7 +14,6 @@ use crate::{ use eth_types::Field; use gadgets::util::{not, pow, Scalar}; use halo2_proofs::{ - circuit::Region, plonk::{Error, Expression}, }; @@ -50,7 +51,7 @@ impl RLPListGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, bytes: &[u8], ) -> Result { @@ -104,8 +105,9 @@ impl RLPListGadget { } /// Number of RLP bytes - pub(crate) fn num_rlp_bytes(&self) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn num_rlp_bytes(&self) -> Expression { + let mut cb = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { self.is_short() => 1.expr(), self.is_long() => 2.expr(), @@ -120,8 +122,9 @@ impl RLPListGadget { } /// Returns the length of the list (excluding RLP bytes) - pub(crate) fn len(&self) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn len(&self) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { self.is_short() => get_len_list_short::expr(self.bytes[0].expr()), self.is_long() => self.bytes[1].expr(), @@ -136,8 +139,9 @@ impl RLPListGadget { } /// Returns the rlc of only the RLP bytes - pub(crate) fn rlc_rlp_only(&self, r: &Expression) -> (Expression, Expression) { - circuit!([meta, _cb!()], { + pub(crate) fn rlc_rlp_only(&self, r: &Expression) -> (Expression, Expression) { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { self.is_short() => (self.bytes[..1].rlc(r), pow::expr(r.expr(), 1)), self.is_long() => (self.bytes[..2].rlc(r), pow::expr(r.expr(), 2)), @@ -231,7 +235,7 @@ impl RLPListDataGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, list_bytes: &[u8], ) -> Result { @@ -278,7 +282,7 @@ impl RLPValueGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, bytes: &[u8], ) -> Result { @@ -334,8 +338,9 @@ impl RLPValueGadget { } /// Number of RLP bytes - pub(crate) fn num_rlp_bytes(&self) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn num_rlp_bytes(&self) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { self.is_short() => 0.expr(), self.is_long() => 1.expr(), @@ -345,8 +350,9 @@ impl RLPValueGadget { } /// Number of bytes in total (including RLP bytes) - pub(crate) fn num_bytes(&self) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn num_bytes(&self) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { self.is_short() => 1.expr(), self.is_long() => get_num_bytes_short::expr(self.bytes[0].expr()), @@ -359,8 +365,9 @@ impl RLPValueGadget { } /// Length of the value (excluding RLP bytes) - pub(crate) fn len(&self) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn len(&self) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { self.is_short() => 1.expr(), self.is_long() => get_len_short::expr(self.bytes[0].expr()), @@ -373,7 +380,7 @@ impl RLPValueGadget { } /// RLC data - pub(crate) fn rlc(&self, r: &Expression) -> (Expression, Expression) { + pub(crate) fn rlc(&self, r: &Expression) -> (Expression, Expression) { (self.rlc_value(r), self.rlc_rlp(r)) } @@ -381,8 +388,9 @@ impl RLPValueGadget { self.bytes.rlc(r) } - pub(crate) fn rlc_value(&self, r: &Expression) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn rlc_value(&self, r: &Expression) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { self.is_short() => { self.bytes[0].expr() @@ -568,7 +576,7 @@ impl RLPItemGadget { pub(crate) fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, offset: usize, bytes: &[u8], ) -> Result { @@ -584,8 +592,9 @@ impl RLPItemGadget { } // Single RLP byte containing the byte value - pub(crate) fn is_short(&self) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn is_short(&self) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.is_short(), self.list.is_list() => self.list.is_short(), @@ -594,8 +603,9 @@ impl RLPItemGadget { } // Single RLP byte containing the length of the value - pub(crate) fn is_long(&self) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn is_long(&self) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.is_long(), self.list.is_list() => self.list.is_long(), @@ -605,8 +615,9 @@ impl RLPItemGadget { // RLP byte containing the lenght of the length, // followed by the length, followed by the actual data - pub(crate) fn is_very_long(&self) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn is_very_long(&self) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.is_very_long(), self.list.is_list() => self.list.is_very_long(), @@ -615,36 +626,39 @@ impl RLPItemGadget { } /// Number of RLP bytes - pub(crate) fn num_rlp_bytes(&self) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn num_rlp_bytes(&self) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { - self.value.is_string() => self.value.num_rlp_bytes::(), - self.list.is_list() => self.list.num_rlp_bytes::(), + self.value.is_string() => self.value.num_rlp_bytes(), + self.list.is_list() => self.list.num_rlp_bytes(), } }) } /// Number of bytes in total (including RLP bytes) - pub(crate) fn num_bytes(&self) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn num_bytes(&self) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { - self.value.is_string() => self.value.num_bytes::(), + self.value.is_string() => self.value.num_bytes(), self.list.is_list() => self.list.num_bytes(), } }) } /// Length of the value (excluding RLP bytes) - pub(crate) fn len(&self) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn len(&self) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { - self.value.is_string() => self.value.len::(), - self.list.is_list() => self.list.len::(), + self.value.is_string() => self.value.len(), + self.list.is_list() => self.list.len(), } }) } - pub(crate) fn rlc_rlp( + pub(crate) fn rlc_rlp( &self, cb: &mut ConstraintBuilder, r: &Expression, @@ -659,10 +673,11 @@ impl RLPItemGadget { // Returns the RLC of the value if the RLP is a string, // returns the RLC of the full string if the RLP is a list. - pub(crate) fn rlc_content(&self, r: &Expression) -> Expression { - circuit!([meta, _cb!()], { + pub(crate) fn rlc_content(&self, r: &Expression) -> Expression { + let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + circuit!([meta, cb], { matchx! { - self.value.is_string() => self.value.rlc_value::(r), + self.value.is_string() => self.value.rlc_value(r), self.list.is_list() => self.list.rlc_rlp(r), } }) diff --git a/zkevm-circuits/src/mpt_circuit/start.rs b/zkevm-circuits/src/mpt_circuit/start.rs index 86109fdbdf..48632332d0 100644 --- a/zkevm-circuits/src/mpt_circuit/start.rs +++ b/zkevm-circuits/src/mpt_circuit/start.rs @@ -5,7 +5,9 @@ use super::{ }; use crate::{ circuit, - circuit_tools::cell_manager::Cell, + circuit_tools::{ + cell_manager::Cell, cached_region::CachedRegion, + }, mpt_circuit::{ helpers::{ key_memory, main_memory, parent_memory, KeyData, MPTConstraintBuilder, MainData, @@ -17,8 +19,7 @@ use crate::{ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - circuit::Region, - plonk::{Error, VirtualCells}, + plonk::{Error, VirtualCells}, circuit::Value, }; #[derive(Clone, Debug, Default)] @@ -82,7 +83,7 @@ impl StartConfig { pub fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, ctx: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs index 6b82441244..d549aaa2b4 100644 --- a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs @@ -11,7 +11,7 @@ use crate::{ circuit_tools::{ cell_manager::Cell, constraint_builder::RLCChainable, - gadgets::{IsEqualGadget, LtGadget}, + gadgets::{IsEqualGadget, LtGadget}, cached_region::CachedRegion, }, mpt_circuit::{ helpers::{ @@ -259,7 +259,7 @@ impl StorageLeafConfig { pub fn assign( &self, - region: &mut Region<'_, F>, + region: &mut CachedRegion<'_, '_, F>, ctx: &MPTConfig, pv: &mut MPTState, offset: usize, @@ -416,7 +416,7 @@ impl StorageLeafConfig { MPTProofType::Disabled }; ctx.mpt_table.assign( - region, + region.region(), offset, &MptUpdateRow { address_rlc: Value::known(main_data.address_rlc), From 5b6c25060622af2c0ebf5a48f4a98f3342bcf436 Mon Sep 17 00:00:00 2001 From: Kimi Wu Date: Thu, 4 May 2023 09:35:42 +0800 Subject: [PATCH 024/102] feat/ #1180 refactor gen_begin_tx_ops and gen_end_tx_ops (#1336) ### Description fix #1180 ### Issue Link #1180 ### Type of change - [x] New feature (non-breaking change which adds functionality) ### Contents see #1180 ### Rationale [_design decisions and extended information_] ### How Has This Been Tested? Pass all the existing test cases --------- Co-authored-by: Han --- bus-mapping/src/circuit_input_builder.rs | 16 +- bus-mapping/src/evm/opcodes.rs | 334 ++------------------ bus-mapping/src/evm/opcodes/begin_end_tx.rs | 333 +++++++++++++++++++ 3 files changed, 364 insertions(+), 319 deletions(-) create mode 100644 bus-mapping/src/evm/opcodes/begin_end_tx.rs diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 37c9a49e77..2c677d1290 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -13,7 +13,7 @@ mod transaction; use self::access::gen_state_access_trace; use crate::{ error::Error, - evm::opcodes::{gen_associated_ops, gen_begin_tx_ops, gen_end_tx_ops}, + evm::opcodes::{gen_associated_ops, gen_associated_steps}, operation::{CallContextField, Operation, RWCounter, StartOp, RW}, rpc::GethClient, state_db::{self, CodeDB, StateDB}, @@ -270,11 +270,11 @@ impl<'a> CircuitInputBuilder { let mut tx = self.new_tx(eth_tx, !geth_trace.failed)?; let mut tx_ctx = TransactionContext::new(eth_tx, geth_trace, is_last_tx)?; - // TODO: Move into gen_associated_steps with - // - execution_state: BeginTx - // - op: None // Generate BeginTx step - let begin_tx_step = gen_begin_tx_ops(&mut self.state_ref(&mut tx, &mut tx_ctx))?; + let begin_tx_step = gen_associated_steps( + &mut self.state_ref(&mut tx, &mut tx_ctx), + ExecState::BeginTx, + )?; tx.steps_mut().push(begin_tx_step); for (index, geth_step) in geth_trace.struct_logs.iter().enumerate() { @@ -288,11 +288,9 @@ impl<'a> CircuitInputBuilder { tx.steps_mut().extend(exec_steps); } - // TODO: Move into gen_associated_steps with - // - execution_state: EndTx - // - op: None // Generate EndTx step - let end_tx_step = gen_end_tx_ops(&mut self.state_ref(&mut tx, &mut tx_ctx))?; + let end_tx_step = + gen_associated_steps(&mut self.state_ref(&mut tx, &mut tx_ctx), ExecState::EndTx)?; tx.steps_mut().push(end_tx_step); self.sdb.commit_tx(); diff --git a/bus-mapping/src/evm/opcodes.rs b/bus-mapping/src/evm/opcodes.rs index 8bd6df7d53..db310525cb 100644 --- a/bus-mapping/src/evm/opcodes.rs +++ b/bus-mapping/src/evm/opcodes.rs @@ -1,27 +1,20 @@ //! Definition of each opcode of the EVM. use crate::{ - circuit_input_builder::{CircuitInputStateRef, ExecStep}, + circuit_input_builder::{CircuitInputStateRef, ExecState, ExecStep}, error::{ExecError, OogError}, evm::OpcodeId, - operation::{ - AccountField, AccountOp, CallContextField, TxAccessListAccountOp, TxReceiptField, - TxRefundOp, RW, - }, - state_db::CodeDB, + operation::TxAccessListAccountOp, Error, }; use core::fmt::Debug; -use eth_types::{ - evm_types::{GasCost, MAX_REFUND_QUOTIENT_OF_GAS_USED}, - evm_unimplemented, GethExecStep, ToAddress, ToWord, Word, -}; -use ethers_core::utils::get_contract_address; +use eth_types::{evm_unimplemented, GethExecStep, ToAddress}; #[cfg(any(feature = "test", test))] pub use self::sha3::sha3_tests::{gen_sha3_code, MemoryKind}; mod address; mod balance; +mod begin_end_tx; mod calldatacopy; mod calldataload; mod calldatasize; @@ -70,6 +63,7 @@ mod memory_expansion_test; use self::sha3::Sha3; use address::Address; use balance::Balance; +use begin_end_tx::BeginEndTx; use calldatacopy::Calldatacopy; use calldataload::Calldataload; use calldatasize::Calldatasize; @@ -123,6 +117,15 @@ pub trait Opcode: Debug { ) -> Result, Error>; } +/// Generic trait for tx execution steps +/// which only supports ExecState::BeginTx and ExecState:EndTx +pub trait TxExecSteps: Debug { + fn gen_associated_steps( + state: &mut CircuitInputStateRef, + execution_step: ExecState, + ) -> Result; +} + #[derive(Debug, Copy, Clone)] struct Dummy; @@ -364,307 +367,18 @@ pub fn gen_associated_ops( fn_gen_associated_ops(state, geth_steps) } -pub fn gen_begin_tx_ops(state: &mut CircuitInputStateRef) -> Result { - let mut exec_step = state.new_begin_tx_step(); - let call = state.call()?.clone(); - - for (field, value) in [ - (CallContextField::TxId, state.tx_ctx.id().into()), - ( - CallContextField::RwCounterEndOfReversion, - call.rw_counter_end_of_reversion.into(), - ), - ( - CallContextField::IsPersistent, - (call.is_persistent as usize).into(), - ), - (CallContextField::IsSuccess, call.is_success.to_word()), - ] { - state.call_context_write(&mut exec_step, call.call_id, field, value); - } - - // Increase caller's nonce - let caller_address = call.caller_address; - let nonce_prev = state.sdb.get_account(&caller_address).1.nonce; - state.account_write( - &mut exec_step, - caller_address, - AccountField::Nonce, - nonce_prev + 1, - nonce_prev, - )?; - - // Add caller and callee into access list - for address in [call.caller_address, call.address] { - let is_warm_prev = !state.sdb.add_account_to_access_list(address); - state.tx_accesslist_account_write( - &mut exec_step, - state.tx_ctx.id(), - address, - true, - is_warm_prev, - )?; - } - - // Calculate intrinsic gas cost - let call_data_gas_cost = state - .tx - .input - .iter() - .fold(0, |acc, byte| acc + if *byte == 0 { 4 } else { 16 }); - let intrinsic_gas_cost = if state.tx.is_create() { - GasCost::CREATION_TX.as_u64() - } else { - GasCost::TX.as_u64() - } + call_data_gas_cost; - exec_step.gas_cost = GasCost(intrinsic_gas_cost); - - // Get code_hash of callee - let (_, callee_account) = state.sdb.get_account(&call.address); - let callee_exists = !callee_account.is_empty(); - let (callee_code_hash, is_empty_code_hash) = if callee_exists { - ( - call.code_hash.to_word(), - call.code_hash == CodeDB::empty_code_hash(), - ) - } else { - (Word::zero(), true) - }; - if !state.is_precompiled(&call.address) && !call.is_create() { - state.account_read( - &mut exec_step, - call.address, - AccountField::CodeHash, - callee_code_hash, - ); - } - - // Transfer with fee - state.transfer_with_fee( - &mut exec_step, - call.caller_address, - call.address, - callee_exists, - call.is_create(), - call.value, - Some(state.tx.gas_price * state.tx.gas), - )?; - - // In case of contract creation we wish to verify the correctness of the - // contract's address (callee). This address is defined as: - // - // Keccak256(RLP([tx_caller, tx_nonce]))[12:] - // - // We feed the RLP-encoded bytes to the block's SHA3 inputs, which gets assigned - // to the Keccak circuit, so that the BeginTxGadget can do a lookup to the - // Keccak table and verify the contract address. - if state.tx.is_create() { - state.block.sha3_inputs.push({ - let mut stream = ethers_core::utils::rlp::RlpStream::new(); - stream.begin_list(2); - stream.append(&caller_address); - stream.append(&nonce_prev); - stream.out().to_vec() - }); - } - - // There are 4 branches from here. - match ( - call.is_create(), - state.is_precompiled(&call.address), - is_empty_code_hash, - ) { - // 1. Creation transaction. - (true, _, _) => { - state.push_op_reversible( - &mut exec_step, - AccountOp { - address: call.address, - field: AccountField::Nonce, - value: 1.into(), - value_prev: 0.into(), - }, - )?; - for (field, value) in [ - (CallContextField::Depth, call.depth.into()), - ( - CallContextField::CallerAddress, - call.caller_address.to_word(), - ), - ( - CallContextField::CalleeAddress, - get_contract_address(caller_address, nonce_prev).to_word(), - ), - ( - CallContextField::CallDataOffset, - call.call_data_offset.into(), - ), - ( - CallContextField::CallDataLength, - state.tx.input.len().into(), - ), - (CallContextField::Value, call.value), - (CallContextField::IsStatic, (call.is_static as usize).into()), - (CallContextField::LastCalleeId, 0.into()), - (CallContextField::LastCalleeReturnDataOffset, 0.into()), - (CallContextField::LastCalleeReturnDataLength, 0.into()), - (CallContextField::IsRoot, 1.into()), - (CallContextField::IsCreate, 1.into()), - (CallContextField::CodeHash, call.code_hash.to_word()), - ] { - state.call_context_write(&mut exec_step, call.call_id, field, value); - } - Ok(exec_step) - } - // 2. Call to precompiled. - (_, true, _) => { - evm_unimplemented!("Call to precompiled is left unimplemented"); - Ok(exec_step) - } - (_, _, is_empty_code_hash) => { - // 3. Call to account with empty code. - if is_empty_code_hash { - return Ok(exec_step); - } - - // 4. Call to account with non-empty code. - for (field, value) in [ - (CallContextField::Depth, call.depth.into()), - ( - CallContextField::CallerAddress, - call.caller_address.to_word(), - ), - (CallContextField::CalleeAddress, call.address.to_word()), - ( - CallContextField::CallDataOffset, - call.call_data_offset.into(), - ), - ( - CallContextField::CallDataLength, - call.call_data_length.into(), - ), - (CallContextField::Value, call.value), - (CallContextField::IsStatic, (call.is_static as usize).into()), - (CallContextField::LastCalleeId, 0.into()), - (CallContextField::LastCalleeReturnDataOffset, 0.into()), - (CallContextField::LastCalleeReturnDataLength, 0.into()), - (CallContextField::IsRoot, 1.into()), - (CallContextField::IsCreate, 0.into()), - (CallContextField::CodeHash, callee_code_hash), - ] { - state.call_context_write(&mut exec_step, call.call_id, field, value); - } - - Ok(exec_step) +pub fn gen_associated_steps( + state: &mut CircuitInputStateRef, + execution_step: ExecState, +) -> Result { + let fn_gen_associated_steps = match execution_step { + ExecState::BeginTx | ExecState::EndTx => BeginEndTx::gen_associated_steps, + _ => { + unreachable!() } - } -} - -pub fn gen_end_tx_ops(state: &mut CircuitInputStateRef) -> Result { - let mut exec_step = state.new_end_tx_step(); - let call = state.tx.calls()[0].clone(); - - state.call_context_read( - &mut exec_step, - call.call_id, - CallContextField::TxId, - state.tx_ctx.id().into(), - ); - state.call_context_read( - &mut exec_step, - call.call_id, - CallContextField::IsPersistent, - Word::from(call.is_persistent as u8), - ); - - let refund = state.sdb.refund(); - state.push_op( - &mut exec_step, - RW::READ, - TxRefundOp { - tx_id: state.tx_ctx.id(), - value: refund, - value_prev: refund, - }, - ); - - let effective_refund = - refund.min((state.tx.gas - exec_step.gas_left.0) / MAX_REFUND_QUOTIENT_OF_GAS_USED as u64); - let (found, caller_account) = state.sdb.get_account(&call.caller_address); - if !found { - return Err(Error::AccountNotFound(call.caller_address)); - } - let caller_balance_prev = caller_account.balance; - let caller_balance = - caller_balance_prev + state.tx.gas_price * (exec_step.gas_left.0 + effective_refund); - state.account_write( - &mut exec_step, - call.caller_address, - AccountField::Balance, - caller_balance, - caller_balance_prev, - )?; - - let effective_tip = state.tx.gas_price - state.block.base_fee; - let (found, coinbase_account) = state.sdb.get_account(&state.block.coinbase); - if !found { - return Err(Error::AccountNotFound(state.block.coinbase)); - } - let coinbase_balance_prev = coinbase_account.balance; - let coinbase_balance = - coinbase_balance_prev + effective_tip * (state.tx.gas - exec_step.gas_left.0); - state.account_write( - &mut exec_step, - state.block.coinbase, - AccountField::Balance, - coinbase_balance, - coinbase_balance_prev, - )?; - - // handle tx receipt tag - state.tx_receipt_write( - &mut exec_step, - state.tx_ctx.id(), - TxReceiptField::PostStateOrStatus, - call.is_persistent as u64, - )?; - - let log_id = exec_step.log_id; - state.tx_receipt_write( - &mut exec_step, - state.tx_ctx.id(), - TxReceiptField::LogLength, - log_id as u64, - )?; - - if state.tx_ctx.id() > 1 { - // query pre tx cumulative gas - state.tx_receipt_read( - &mut exec_step, - state.tx_ctx.id() - 1, - TxReceiptField::CumulativeGasUsed, - state.block_ctx.cumulative_gas_used, - )?; - } - - state.block_ctx.cumulative_gas_used += state.tx.gas - exec_step.gas_left.0; - state.tx_receipt_write( - &mut exec_step, - state.tx_ctx.id(), - TxReceiptField::CumulativeGasUsed, - state.block_ctx.cumulative_gas_used, - )?; - - if !state.tx_ctx.is_last_tx() { - state.call_context_write( - &mut exec_step, - state.block_ctx.rwc.0 + 1, - CallContextField::TxId, - (state.tx_ctx.id() + 1).into(), - ); - } + }; - Ok(exec_step) + fn_gen_associated_steps(state, execution_step) } #[derive(Debug, Copy, Clone)] diff --git a/bus-mapping/src/evm/opcodes/begin_end_tx.rs b/bus-mapping/src/evm/opcodes/begin_end_tx.rs new file mode 100644 index 0000000000..da9bff4f79 --- /dev/null +++ b/bus-mapping/src/evm/opcodes/begin_end_tx.rs @@ -0,0 +1,333 @@ +use super::TxExecSteps; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecState, ExecStep}, + operation::{AccountField, AccountOp, CallContextField, TxReceiptField, TxRefundOp, RW}, + state_db::CodeDB, + Error, +}; +use eth_types::{ + evm_types::{GasCost, MAX_REFUND_QUOTIENT_OF_GAS_USED}, + evm_unimplemented, ToWord, Word, +}; +use ethers_core::utils::get_contract_address; + +#[derive(Clone, Copy, Debug)] +pub(crate) struct BeginEndTx; + +impl TxExecSteps for BeginEndTx { + fn gen_associated_steps( + state: &mut CircuitInputStateRef, + execution_step: ExecState, + ) -> Result { + match execution_step { + ExecState::BeginTx => gen_begin_tx_steps(state), + ExecState::EndTx => gen_end_tx_steps(state), + _ => { + unreachable!() + } + } + } +} + +fn gen_begin_tx_steps(state: &mut CircuitInputStateRef) -> Result { + let mut exec_step = state.new_begin_tx_step(); + let call = state.call()?.clone(); + + for (field, value) in [ + (CallContextField::TxId, state.tx_ctx.id().into()), + ( + CallContextField::RwCounterEndOfReversion, + call.rw_counter_end_of_reversion.into(), + ), + ( + CallContextField::IsPersistent, + (call.is_persistent as usize).into(), + ), + (CallContextField::IsSuccess, call.is_success.to_word()), + ] { + state.call_context_write(&mut exec_step, call.call_id, field, value); + } + + // Increase caller's nonce + let caller_address = call.caller_address; + let nonce_prev = state.sdb.get_account(&caller_address).1.nonce; + state.account_write( + &mut exec_step, + caller_address, + AccountField::Nonce, + nonce_prev + 1, + nonce_prev, + )?; + + // Add caller and callee into access list + for address in [call.caller_address, call.address] { + let is_warm_prev = !state.sdb.add_account_to_access_list(address); + state.tx_accesslist_account_write( + &mut exec_step, + state.tx_ctx.id(), + address, + true, + is_warm_prev, + )?; + } + + // Calculate intrinsic gas cost + let call_data_gas_cost = state + .tx + .input + .iter() + .fold(0, |acc, byte| acc + if *byte == 0 { 4 } else { 16 }); + let intrinsic_gas_cost = if state.tx.is_create() { + GasCost::CREATION_TX.as_u64() + } else { + GasCost::TX.as_u64() + } + call_data_gas_cost; + exec_step.gas_cost = GasCost(intrinsic_gas_cost); + + // Get code_hash of callee + let (_, callee_account) = state.sdb.get_account(&call.address); + let callee_exists = !callee_account.is_empty(); + let (callee_code_hash, is_empty_code_hash) = if callee_exists { + ( + call.code_hash.to_word(), + call.code_hash == CodeDB::empty_code_hash(), + ) + } else { + (Word::zero(), true) + }; + if !state.is_precompiled(&call.address) && !call.is_create() { + state.account_read( + &mut exec_step, + call.address, + AccountField::CodeHash, + callee_code_hash, + ); + } + + // Transfer with fee + state.transfer_with_fee( + &mut exec_step, + call.caller_address, + call.address, + callee_exists, + call.is_create(), + call.value, + Some(state.tx.gas_price * state.tx.gas), + )?; + + // In case of contract creation we wish to verify the correctness of the + // contract's address (callee). This address is defined as: + // + // Keccak256(RLP([tx_caller, tx_nonce]))[12:] + // + // We feed the RLP-encoded bytes to the block's SHA3 inputs, which gets assigned + // to the Keccak circuit, so that the BeginTxGadget can do a lookup to the + // Keccak table and verify the contract address. + if state.tx.is_create() { + state.block.sha3_inputs.push({ + let mut stream = ethers_core::utils::rlp::RlpStream::new(); + stream.begin_list(2); + stream.append(&caller_address); + stream.append(&nonce_prev); + stream.out().to_vec() + }); + } + + // There are 4 branches from here. + match ( + call.is_create(), + state.is_precompiled(&call.address), + is_empty_code_hash, + ) { + // 1. Creation transaction. + (true, _, _) => { + state.push_op_reversible( + &mut exec_step, + AccountOp { + address: call.address, + field: AccountField::Nonce, + value: 1.into(), + value_prev: 0.into(), + }, + )?; + for (field, value) in [ + (CallContextField::Depth, call.depth.into()), + ( + CallContextField::CallerAddress, + call.caller_address.to_word(), + ), + ( + CallContextField::CalleeAddress, + get_contract_address(caller_address, nonce_prev).to_word(), + ), + ( + CallContextField::CallDataOffset, + call.call_data_offset.into(), + ), + ( + CallContextField::CallDataLength, + state.tx.input.len().into(), + ), + (CallContextField::Value, call.value), + (CallContextField::IsStatic, (call.is_static as usize).into()), + (CallContextField::LastCalleeId, 0.into()), + (CallContextField::LastCalleeReturnDataOffset, 0.into()), + (CallContextField::LastCalleeReturnDataLength, 0.into()), + (CallContextField::IsRoot, 1.into()), + (CallContextField::IsCreate, 1.into()), + (CallContextField::CodeHash, call.code_hash.to_word()), + ] { + state.call_context_write(&mut exec_step, call.call_id, field, value); + } + Ok(exec_step) + } + // 2. Call to precompiled. + (_, true, _) => { + evm_unimplemented!("Call to precompiled is left unimplemented"); + Ok(exec_step) + } + (_, _, is_empty_code_hash) => { + // 3. Call to account with empty code. + if is_empty_code_hash { + return Ok(exec_step); + } + + // 4. Call to account with non-empty code. + for (field, value) in [ + (CallContextField::Depth, call.depth.into()), + ( + CallContextField::CallerAddress, + call.caller_address.to_word(), + ), + (CallContextField::CalleeAddress, call.address.to_word()), + ( + CallContextField::CallDataOffset, + call.call_data_offset.into(), + ), + ( + CallContextField::CallDataLength, + call.call_data_length.into(), + ), + (CallContextField::Value, call.value), + (CallContextField::IsStatic, (call.is_static as usize).into()), + (CallContextField::LastCalleeId, 0.into()), + (CallContextField::LastCalleeReturnDataOffset, 0.into()), + (CallContextField::LastCalleeReturnDataLength, 0.into()), + (CallContextField::IsRoot, 1.into()), + (CallContextField::IsCreate, 0.into()), + (CallContextField::CodeHash, callee_code_hash), + ] { + state.call_context_write(&mut exec_step, call.call_id, field, value); + } + + Ok(exec_step) + } + } +} + +fn gen_end_tx_steps(state: &mut CircuitInputStateRef) -> Result { + let mut exec_step = state.new_end_tx_step(); + let call = state.tx.calls()[0].clone(); + + state.call_context_read( + &mut exec_step, + call.call_id, + CallContextField::TxId, + state.tx_ctx.id().into(), + ); + state.call_context_read( + &mut exec_step, + call.call_id, + CallContextField::IsPersistent, + Word::from(call.is_persistent as u8), + ); + + let refund = state.sdb.refund(); + state.push_op( + &mut exec_step, + RW::READ, + TxRefundOp { + tx_id: state.tx_ctx.id(), + value: refund, + value_prev: refund, + }, + ); + + let effective_refund = + refund.min((state.tx.gas - exec_step.gas_left.0) / MAX_REFUND_QUOTIENT_OF_GAS_USED as u64); + let (found, caller_account) = state.sdb.get_account(&call.caller_address); + if !found { + return Err(Error::AccountNotFound(call.caller_address)); + } + let caller_balance_prev = caller_account.balance; + let caller_balance = + caller_balance_prev + state.tx.gas_price * (exec_step.gas_left.0 + effective_refund); + state.account_write( + &mut exec_step, + call.caller_address, + AccountField::Balance, + caller_balance, + caller_balance_prev, + )?; + + let effective_tip = state.tx.gas_price - state.block.base_fee; + let (found, coinbase_account) = state.sdb.get_account(&state.block.coinbase); + if !found { + return Err(Error::AccountNotFound(state.block.coinbase)); + } + let coinbase_balance_prev = coinbase_account.balance; + let coinbase_balance = + coinbase_balance_prev + effective_tip * (state.tx.gas - exec_step.gas_left.0); + state.account_write( + &mut exec_step, + state.block.coinbase, + AccountField::Balance, + coinbase_balance, + coinbase_balance_prev, + )?; + + // handle tx receipt tag + state.tx_receipt_write( + &mut exec_step, + state.tx_ctx.id(), + TxReceiptField::PostStateOrStatus, + call.is_persistent as u64, + )?; + + let log_id = exec_step.log_id; + state.tx_receipt_write( + &mut exec_step, + state.tx_ctx.id(), + TxReceiptField::LogLength, + log_id as u64, + )?; + + if state.tx_ctx.id() > 1 { + // query pre tx cumulative gas + state.tx_receipt_read( + &mut exec_step, + state.tx_ctx.id() - 1, + TxReceiptField::CumulativeGasUsed, + state.block_ctx.cumulative_gas_used, + )?; + } + + state.block_ctx.cumulative_gas_used += state.tx.gas - exec_step.gas_left.0; + state.tx_receipt_write( + &mut exec_step, + state.tx_ctx.id(), + TxReceiptField::CumulativeGasUsed, + state.block_ctx.cumulative_gas_used, + )?; + + if !state.tx_ctx.is_last_tx() { + state.call_context_write( + &mut exec_step, + state.block_ctx.rwc.0 + 1, + CallContextField::TxId, + (state.tx_ctx.id() + 1).into(), + ); + } + + Ok(exec_step) +} From a04940ce8acc00559ca920d33f4bd10de25c5866 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Thu, 4 May 2023 11:21:25 +0800 Subject: [PATCH 025/102] updates, still needs to fix CM --- zkevm-circuits/src/circuit_tools.rs | 1 + .../src/circuit_tools/cached_region.rs | 5 +-- .../src/circuit_tools/cell_manager.rs | 40 ++++++++++--------- .../src/circuit_tools/constraint_builder.rs | 4 +- zkevm-circuits/src/circuit_tools/gadgets.rs | 6 +-- zkevm-circuits/src/mpt_circuit.rs | 10 ++--- .../src/mpt_circuit/account_leaf.rs | 4 +- .../src/mpt_circuit/storage_leaf.rs | 4 +- zkevm-circuits/src/mpt_circuit/table.rs | 2 +- zkevm-circuits/src/table.rs | 17 +++++++- 10 files changed, 56 insertions(+), 37 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools.rs b/zkevm-circuits/src/circuit_tools.rs index 677dfd33bb..02270ce17c 100644 --- a/zkevm-circuits/src/circuit_tools.rs +++ b/zkevm-circuits/src/circuit_tools.rs @@ -1,4 +1,5 @@ //! Circuit utilities +#![allow(missing_docs)] #[macro_use] pub mod constraint_builder; pub mod cell_manager; diff --git a/zkevm-circuits/src/circuit_tools/cached_region.rs b/zkevm-circuits/src/circuit_tools/cached_region.rs index b2205a1173..d388ae0b5a 100644 --- a/zkevm-circuits/src/circuit_tools/cached_region.rs +++ b/zkevm-circuits/src/circuit_tools/cached_region.rs @@ -126,15 +126,12 @@ impl<'r, 'b, F: Field> CachedRegion<'r, 'b, F> { unimplemented!("fixed column"); } + // StoreExpression 里面调,拿 F 出去 evaluate pub fn get_advice(&self, row_index: usize, column_index: usize, rotation: Rotation) -> F { self.advice[column_index - self.width_start] [(((row_index - self.height_start) as i32) + rotation.0) as usize] } - pub fn region(&mut self) -> &mut Region<'_, F> { - self.region - } - pub fn challenges(&self) -> &Challenges> { self.challenges } diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index bbea1ea754..49fa89402a 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -94,13 +94,13 @@ impl Cell { impl Expr for Cell { fn expr(&self) -> Expression { - self.expression.unwrap().clone() + self.expression.as_ref().unwrap().clone() } } impl Expr for &Cell { fn expr(&self) -> Expression { - self.expression.unwrap().clone() + self.expression.as_ref().unwrap().clone() } } @@ -182,10 +182,10 @@ impl CellType_ { #[derive(Clone, Debug)] pub(crate) struct CellColumn { - pub(crate) index: usize, - pub(crate) cell_type: CellType_, - pub(crate) height: usize, - pub(crate) expr: Expression, + index: usize, + cell_type: CellType_, + height: usize, + expr: Expression, } impl Expr for CellColumn { @@ -195,15 +195,19 @@ impl Expr for CellColumn { } #[derive(Clone, Debug)] -pub(crate) struct CellManager { - width: usize, - height: usize, - cells: Vec>, +pub struct CellManager { + // Thoughts (Cecilia): Integrate CellManager's function into Halo2's VirtualCell + // They do the same things by saving queried Exressions + // CM is just slightly smarter. + // Make VC into trait, let CM impl VC. + pub(crate) width: usize, + pub(crate) height: usize, + pub(crate) cells: Vec>, // 对cell的抽象表示和对columns的抽象表示是分开的 // Cell 不用 T - columns: Vec>, - phase_config: PhaseConfig, - copy_columns: usize, + pub(crate) columns: Vec>, + pub(crate) phase_config: PhaseConfig, + pub(crate) copy_columns: usize, } #[derive(Clone, Debug)] @@ -215,8 +219,8 @@ pub struct PhaseConfig { impl CellManager { pub(crate) fn new( - meta: &mut ConstraintSystem, - height: usize, + meta: &mut ConstraintSystem, // meta只出现一次,new的时候把所有cover的cells都query一遍 + height: usize, // 拿到 Expr 存起来,后面 cb.query_cell 直接给对应格子的 Expr advices: &[Column], height_offset: usize, phase_config: PhaseConfig, @@ -247,9 +251,9 @@ impl CellManager { let mut column_idx = 0; // Mark columns used for lookups in Phase3 - for (table, count) in phase_config.phase3 { - for _ in 0usize..count { - columns[column_idx].cell_type = CellType_::Lookup(table); + for (table, count) in &phase_config.phase3 { + for _ in 0usize..*count { + columns[column_idx].cell_type = CellType_::Lookup(table.clone()); column_idx += 1; } } diff --git a/zkevm-circuits/src/circuit_tools/constraint_builder.rs b/zkevm-circuits/src/circuit_tools/constraint_builder.rs index 7b02b3d444..2725e56aba 100644 --- a/zkevm-circuits/src/circuit_tools/constraint_builder.rs +++ b/zkevm-circuits/src/circuit_tools/constraint_builder.rs @@ -152,9 +152,10 @@ impl ConstraintBuilder { } fn query_cells_dyn(&mut self, cell_type: CellType_, count: usize) -> Vec> { + // cb 对 cm 仅有一个调度接口,即 query_cells self.cell_manager .as_mut() - .unwrap() + .expect("Cell manager not set") .query_cells(cell_type, count) } @@ -171,6 +172,7 @@ impl ConstraintBuilder { } pub(crate) fn generate_constraints(&self) -> Vec<(&'static str, Expression)> { + // 这里没有 self.constraints.clone() } diff --git a/zkevm-circuits/src/circuit_tools/gadgets.rs b/zkevm-circuits/src/circuit_tools/gadgets.rs index 154e5b6b2d..7ed55c8abe 100644 --- a/zkevm-circuits/src/circuit_tools/gadgets.rs +++ b/zkevm-circuits/src/circuit_tools/gadgets.rs @@ -46,7 +46,7 @@ impl IsZeroGadget { value: F, ) -> Result { let inverse = value.invert().unwrap_or(F::zero()); - self.inverse.unwrap().assign(region, offset, inverse)?; + self.inverse.as_ref().unwrap().assign(region, offset, inverse)?; Ok(if value.is_zero().into() { F::one() } else { @@ -129,7 +129,7 @@ impl LtGadget { } pub(crate) fn expr(&self) -> Expression { - self.lt.unwrap().expr() + self.lt.as_ref().unwrap().expr() } pub(crate) fn assign( @@ -141,7 +141,7 @@ impl LtGadget { ) -> Result<(F, Vec), Error> { // Set `lt` let lt = lhs < rhs; - self.lt.unwrap() + self.lt.as_ref().unwrap() .assign(region, offset, if lt { F::one() } else { F::zero() })?; // Set the bytes of diff diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 2164ea0a42..989c2024db 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -222,15 +222,15 @@ impl MPTConfig { ifx!{f!(q_enable) => { // RLP item decoding unit - let mut cell_manager = CellManager::new(meta, &rlp_columns); - cell_manager.reset(1); - cb.base.set_cell_manager(cell_manager); + // let mut cell_manager = CellManager::new(meta, 1, &rlp_columns, 0); + // cell_manager.reset(1); + // cb.base.set_cell_manager(cell_manager); rlp_item = MainRLPGadget::construct(&mut cb, &ctx.r); ctx.rlp_item = rlp_item.clone(); // Main MPT circuit - let cell_manager = CellManager::new(meta, &managed_columns); - cb.base.set_cell_manager(cell_manager); + // let cell_manager = CellManager::new(meta, &managed_columns); + // cb.base.set_cell_manager(cell_manager); // State machine // TODO(Brecht): state machine constraints diff --git a/zkevm-circuits/src/mpt_circuit/account_leaf.rs b/zkevm-circuits/src/mpt_circuit/account_leaf.rs index 2a5a0996dd..f09f455060 100644 --- a/zkevm-circuits/src/mpt_circuit/account_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/account_leaf.rs @@ -571,8 +571,8 @@ impl AccountLeafConfig { } else { (MPTProofType::Disabled, vec![0.scalar(); 2]) }; - ctx.mpt_table.assign( - region.region(), + ctx.mpt_table.assign_cached( + region, offset, &MptUpdateRow { address_rlc: Value::known(account.address.rlc_value(pv.r)), diff --git a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs index d549aaa2b4..8757c69b26 100644 --- a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs @@ -415,8 +415,8 @@ impl StorageLeafConfig { } else { MPTProofType::Disabled }; - ctx.mpt_table.assign( - region.region(), + ctx.mpt_table.assign_cached( + region, offset, &MptUpdateRow { address_rlc: Value::known(main_data.address_rlc), diff --git a/zkevm-circuits/src/mpt_circuit/table.rs b/zkevm-circuits/src/mpt_circuit/table.rs index 6add9a7221..e32176dc75 100644 --- a/zkevm-circuits/src/mpt_circuit/table.rs +++ b/zkevm-circuits/src/mpt_circuit/table.rs @@ -3,7 +3,7 @@ use strum_macros::EnumIter; use crate::circuit_tools::cell_manager::CustomTable; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] -pub(crate) enum Table { +pub enum Table { Fixed, Tx, Rw, diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 90f8b05887..9667bcc2ae 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -2,7 +2,7 @@ use crate::{ circuit, - circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::CustomTable}, + circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::CustomTable, cached_region::CachedRegion}, copy_circuit::number_or_hash_to_field, evm_circuit::util::rlc, exp_circuit::{OFFSET_INCREMENT, ROWS_PER_STEP}, @@ -695,6 +695,21 @@ impl MptTable { Ok(()) } + pub(crate) fn assign_cached( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + row: &MptUpdateRow>, + ) -> Result<(), Error> { + for (column, value) in >::advice_columns(self) + .iter() + .zip_eq(row.values()) + { + region.assign_advice(|| "assign mpt table row value", *column, offset, || value)?; + } + Ok(()) + } + pub(crate) fn load( &self, layouter: &mut impl Layouter, From 68e3d985a2caa766709a03d36d5faa808a780930 Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Thu, 4 May 2023 15:47:52 +0800 Subject: [PATCH 026/102] Prune tx struct fields and rm witness Call (#1378) ### Description We tried to remove some unused tx structs. ### Issue Link #528 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - Remove zkevm-circuits/src/witness/call.rs and the `Call` struct - Remove fields in circuit_input_builder Transaction struct. Reuse Geth type Transaction struct whenever possible - Remove duplicated call data gas cost computation - Add APIs to get "To" address so that we know when we want contract address or zero address. ### Rationale We try to start the de-duplication from the low-hanging fruits. So I didn't remove the witness.rs Transaction struct in this PR. ### How Has This Been Tested? Local build tests and quick tests --- bus-mapping/src/circuit_input_builder.rs | 4 +- .../src/circuit_input_builder/access.rs | 2 +- bus-mapping/src/circuit_input_builder/call.rs | 2 +- .../src/circuit_input_builder/execution.rs | 30 ++----- .../circuit_input_builder/input_state_ref.rs | 2 +- .../src/circuit_input_builder/transaction.rs | 80 +++---------------- bus-mapping/src/evm/opcodes/begin_end_tx.rs | 24 +++--- bus-mapping/src/evm/opcodes/logs.rs | 2 +- bus-mapping/src/evm/opcodes/selfbalance.rs | 2 +- eth-types/src/evm_types.rs | 4 +- eth-types/src/geth_types.rs | 53 +++++++++++- testool/src/statetest/executor.rs | 24 ++---- .../src/evm_circuit/execution/address.rs | 2 +- .../src/evm_circuit/execution/codecopy.rs | 4 +- .../execution/error_invalid_jump.rs | 4 +- .../execution/error_oog_sload_sstore.rs | 2 +- .../src/evm_circuit/execution/logs.rs | 2 +- .../evm_circuit/execution/return_revert.rs | 10 +-- .../src/evm_circuit/execution/selfbalance.rs | 2 +- .../src/evm_circuit/execution/sload.rs | 2 +- .../src/evm_circuit/execution/sstore.rs | 2 +- .../src/evm_circuit/execution/stop.rs | 4 +- zkevm-circuits/src/evm_circuit/step.rs | 13 ++- zkevm-circuits/src/pi_circuit.rs | 16 ++-- zkevm-circuits/src/tx_circuit.rs | 30 ++----- zkevm-circuits/src/witness.rs | 3 +- zkevm-circuits/src/witness/call.rs | 42 ---------- zkevm-circuits/src/witness/tx.rs | 47 +++-------- 28 files changed, 139 insertions(+), 275 deletions(-) delete mode 100644 zkevm-circuits/src/witness/call.rs diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 2c677d1290..2f351c84cf 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -215,7 +215,7 @@ impl<'a> CircuitInputBuilder { end_block_not_last.rwc = self.block_ctx.rwc; end_block_last.rwc = self.block_ctx.rwc; - let mut dummy_tx = Transaction::dummy(); + let mut dummy_tx = Transaction::default(); let mut dummy_tx_ctx = TransactionContext::default(); let mut state = self.state_ref(&mut dummy_tx, &mut dummy_tx_ctx); @@ -305,7 +305,7 @@ impl<'a> CircuitInputBuilder { pub fn keccak_inputs(block: &Block, code_db: &CodeDB) -> Result>, Error> { let mut keccak_inputs = Vec::new(); // Tx Circuit - let txs: Vec = block.txs.iter().map(|tx| tx.into()).collect(); + let txs: Vec = block.txs.iter().map(|tx| tx.tx.clone()).collect(); keccak_inputs.extend_from_slice(&keccak_inputs_tx_circuit(&txs, block.chain_id.as_u64())?); // Bytecode Circuit for bytecode in code_db.0.values() { diff --git a/bus-mapping/src/circuit_input_builder/access.rs b/bus-mapping/src/circuit_input_builder/access.rs index d408138015..1626d6f97a 100644 --- a/bus-mapping/src/circuit_input_builder/access.rs +++ b/bus-mapping/src/circuit_input_builder/access.rs @@ -95,7 +95,7 @@ impl From> for AccessSet { } /// Source of the code in the EVM execution. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CodeSource { /// Code comes from a deployed contract at `Address`. Address(Address), diff --git a/bus-mapping/src/circuit_input_builder/call.rs b/bus-mapping/src/circuit_input_builder/call.rs index 76fcc43280..39a484ea14 100644 --- a/bus-mapping/src/circuit_input_builder/call.rs +++ b/bus-mapping/src/circuit_input_builder/call.rs @@ -51,7 +51,7 @@ impl TryFrom for CallKind { } /// Circuit Input related to an Ethereum Call -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct Call { /// Unique call identifier within the Block. pub call_id: usize, diff --git a/bus-mapping/src/circuit_input_builder/execution.rs b/bus-mapping/src/circuit_input_builder/execution.rs index 2ffd2a4b52..e142d257dc 100644 --- a/bus-mapping/src/circuit_input_builder/execution.rs +++ b/bus-mapping/src/circuit_input_builder/execution.rs @@ -13,7 +13,7 @@ use halo2_proofs::plonk::Expression; use strum_macros::EnumIter; /// An execution step of the EVM. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct ExecStep { /// Execution state pub exec_state: ExecState, @@ -88,28 +88,6 @@ impl ExecStep { } } -impl Default for ExecStep { - fn default() -> Self { - Self { - exec_state: ExecState::Op(OpcodeId::INVALID(0)), - pc: ProgramCounter(0), - stack_size: 0, - memory_size: 0, - gas_left: Gas(0), - gas_cost: GasCost(0), - gas_refund: Gas(0), - call_index: 0, - rwc: RWCounter(0), - reversible_write_counter: 0, - reversible_write_counter_delta: 0, - log_id: 0, - bus_mapping_instance: Vec::new(), - copy_rw_counter_delta: 0, - error: None, - } - } -} - /// Execution state #[derive(Clone, Debug, Eq, PartialEq)] pub enum ExecState { @@ -123,6 +101,12 @@ pub enum ExecState { EndBlock, } +impl Default for ExecState { + fn default() -> Self { + ExecState::Op(OpcodeId::STOP) + } +} + impl ExecState { /// Returns `true` if `ExecState` is an opcode and the opcode is a `PUSHn`. pub fn is_push(&self) -> bool { diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index d57b698904..21124ad6d7 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -60,7 +60,7 @@ impl<'a> CircuitInputStateRef<'a> { pub fn new_begin_tx_step(&self) -> ExecStep { ExecStep { exec_state: ExecState::BeginTx, - gas_left: Gas(self.tx.gas), + gas_left: Gas(self.tx.gas()), rwc: self.block_ctx.rwc, ..Default::default() } diff --git a/bus-mapping/src/circuit_input_builder/transaction.rs b/bus-mapping/src/circuit_input_builder/transaction.rs index 1718772cfd..dae4f1db35 100644 --- a/bus-mapping/src/circuit_input_builder/transaction.rs +++ b/bus-mapping/src/circuit_input_builder/transaction.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; -use eth_types::{evm_types::Memory, geth_types, Address, GethExecTrace, Signature, Word}; +use eth_types::{evm_types::Memory, geth_types, GethExecTrace}; use ethers_core::utils::get_contract_address; use crate::{ @@ -176,70 +176,18 @@ impl TransactionContext { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] /// Result of the parsing of an Ethereum Transaction. pub struct Transaction { - /// Nonce - pub nonce: u64, - /// Gas - pub gas: u64, - /// Gas price - pub gas_price: Word, - /// From / Caller Address - pub from: Address, - /// To / Callee Address - pub to: Address, - /// Value - pub value: Word, - /// Input / Call Data - pub input: Vec, - /// Signature - pub signature: Signature, + /// The raw transaction fields + pub tx: geth_types::Transaction, /// Calls made in the transaction pub(crate) calls: Vec, /// Execution steps steps: Vec, } -impl From<&Transaction> for geth_types::Transaction { - fn from(tx: &Transaction) -> geth_types::Transaction { - geth_types::Transaction { - from: tx.from, - to: Some(tx.to), - nonce: Word::from(tx.nonce), - gas_limit: Word::from(tx.gas), - value: tx.value, - gas_price: tx.gas_price, - call_data: tx.input.clone().into(), - v: tx.signature.v, - r: tx.signature.r, - s: tx.signature.s, - ..Default::default() - } - } -} - impl Transaction { - /// Create a dummy Transaction with zero values - pub fn dummy() -> Self { - Self { - nonce: 0, - gas: 0, - gas_price: Word::zero(), - from: Address::zero(), - to: Address::zero(), - value: Word::zero(), - input: Vec::new(), - signature: Signature { - r: Word::zero(), - s: Word::zero(), - v: 0, - }, - calls: Vec::new(), - steps: Vec::new(), - } - } - /// Create a new Self. pub fn new( call_id: usize, @@ -296,22 +244,9 @@ impl Transaction { }; Ok(Self { - nonce: eth_tx.nonce.as_u64(), - gas: eth_tx.gas.as_u64(), - gas_price: eth_tx.gas_price.unwrap_or_default(), - from: eth_tx.from, - to: eth_tx - .to - .unwrap_or_else(|| get_contract_address(eth_tx.from, eth_tx.nonce)), - value: eth_tx.value, - input: eth_tx.input.to_vec(), + tx: eth_tx.into(), calls: vec![call], steps: Vec::new(), - signature: Signature { - v: eth_tx.v.as_u64(), - r: eth_tx.r, - s: eth_tx.s, - }, }) } @@ -359,4 +294,9 @@ impl Transaction { pub fn is_steps_empty(&self) -> bool { self.steps.is_empty() } + + /// Convinient method for gas limit + pub fn gas(&self) -> u64 { + self.tx.gas_limit.as_u64() + } } diff --git a/bus-mapping/src/evm/opcodes/begin_end_tx.rs b/bus-mapping/src/evm/opcodes/begin_end_tx.rs index da9bff4f79..55cc87dff9 100644 --- a/bus-mapping/src/evm/opcodes/begin_end_tx.rs +++ b/bus-mapping/src/evm/opcodes/begin_end_tx.rs @@ -71,17 +71,11 @@ fn gen_begin_tx_steps(state: &mut CircuitInputStateRef) -> Result Result Result Result }, ); - let effective_refund = - refund.min((state.tx.gas - exec_step.gas_left.0) / MAX_REFUND_QUOTIENT_OF_GAS_USED as u64); + let effective_refund = refund + .min((state.tx.gas() - exec_step.gas_left.0) / MAX_REFUND_QUOTIENT_OF_GAS_USED as u64); let (found, caller_account) = state.sdb.get_account(&call.caller_address); if !found { return Err(Error::AccountNotFound(call.caller_address)); } let caller_balance_prev = caller_account.balance; let caller_balance = - caller_balance_prev + state.tx.gas_price * (exec_step.gas_left.0 + effective_refund); + caller_balance_prev + state.tx.tx.gas_price * (exec_step.gas_left.0 + effective_refund); state.account_write( &mut exec_step, call.caller_address, @@ -270,14 +264,14 @@ fn gen_end_tx_steps(state: &mut CircuitInputStateRef) -> Result caller_balance_prev, )?; - let effective_tip = state.tx.gas_price - state.block.base_fee; + let effective_tip = state.tx.tx.gas_price - state.block.base_fee; let (found, coinbase_account) = state.sdb.get_account(&state.block.coinbase); if !found { return Err(Error::AccountNotFound(state.block.coinbase)); } let coinbase_balance_prev = coinbase_account.balance; let coinbase_balance = - coinbase_balance_prev + effective_tip * (state.tx.gas - exec_step.gas_left.0); + coinbase_balance_prev + effective_tip * (state.tx.gas() - exec_step.gas_left.0); state.account_write( &mut exec_step, state.block.coinbase, @@ -312,7 +306,7 @@ fn gen_end_tx_steps(state: &mut CircuitInputStateRef) -> Result )?; } - state.block_ctx.cumulative_gas_used += state.tx.gas - exec_step.gas_left.0; + state.block_ctx.cumulative_gas_used += state.tx.gas() - exec_step.gas_left.0; state.tx_receipt_write( &mut exec_step, state.tx_ctx.id(), diff --git a/bus-mapping/src/evm/opcodes/logs.rs b/bus-mapping/src/evm/opcodes/logs.rs index aa68440c6d..70b1a98041 100644 --- a/bus-mapping/src/evm/opcodes/logs.rs +++ b/bus-mapping/src/evm/opcodes/logs.rs @@ -291,7 +291,7 @@ mod log_tests { .unwrap(); let is_persistent = builder.block.txs()[0].calls()[0].is_persistent; - let callee_address = builder.block.txs()[0].to; + let callee_address = builder.block.txs()[0].tx.to_or_contract_addr(); let step = builder.block.txs()[0] .steps() diff --git a/bus-mapping/src/evm/opcodes/selfbalance.rs b/bus-mapping/src/evm/opcodes/selfbalance.rs index 671ebfff11..e77294b859 100644 --- a/bus-mapping/src/evm/opcodes/selfbalance.rs +++ b/bus-mapping/src/evm/opcodes/selfbalance.rs @@ -91,7 +91,7 @@ mod selfbalance_tests { .unwrap(); let call_id = builder.block.txs()[0].calls()[0].call_id; - let callee_address = builder.block.txs()[0].to; + let callee_address = builder.block.txs()[0].tx.to_or_contract_addr(); let self_balance = builder.sdb.get_account(&callee_address).1.balance; assert_eq!( diff --git a/eth-types/src/evm_types.rs b/eth-types/src/evm_types.rs index bea6ef9319..9837d79251 100644 --- a/eth-types/src/evm_types.rs +++ b/eth-types/src/evm_types.rs @@ -15,7 +15,7 @@ pub use stack::{Stack, StackAddress}; pub use storage::Storage; /// Wrapper type over `usize` which represents the program counter of the Evm. -#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, PartialOrd, Ord)] +#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, PartialOrd, Ord, Default)] pub struct ProgramCounter(pub usize); impl fmt::Debug for ProgramCounter { @@ -66,7 +66,7 @@ pub const MAX_REFUND_QUOTIENT_OF_GAS_USED: usize = 5; pub const GAS_STIPEND_CALL_WITH_VALUE: u64 = 2300; /// Defines the gas consumption. -#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Default)] pub struct GasCost(pub u64); impl fmt::Debug for GasCost { diff --git a/eth-types/src/geth_types.rs b/eth-types/src/geth_types.rs index 818c544163..ecd265e469 100644 --- a/eth-types/src/geth_types.rs +++ b/eth-types/src/geth_types.rs @@ -5,7 +5,10 @@ use crate::{ AccessList, Address, Block, Bytes, Error, GethExecTrace, Hash, ToBigEndian, ToLittleEndian, Word, U64, }; -use ethers_core::types::{NameOrAddress, TransactionRequest}; +use ethers_core::{ + types::{transaction::response, NameOrAddress, TransactionRequest}, + utils::get_contract_address, +}; use ethers_signers::{LocalWallet, Signer}; use halo2_proofs::halo2curves::{group::ff::PrimeField, secp256k1}; use num::Integer; @@ -113,6 +116,7 @@ pub struct Transaction { /// Sender address pub from: Address, /// Recipient address (None for contract creation) + /// Avoid direct read from this field. We set this field public to construct the struct pub to: Option
, /// Transaction nonce pub nonce: Word, @@ -237,6 +241,53 @@ impl Transaction { msg_hash, }) } + + /// Compute call data gas cost from call data + pub fn call_data_gas_cost(&self) -> u64 { + self.call_data + .iter() + .fold(0, |acc, byte| acc + if *byte == 0 { 4 } else { 16 }) + } + + /// Get the "to" address. If `to` is None then zero adddress + pub fn to_or_zero(&self) -> Address { + self.to.unwrap_or_default() + } + /// Get the "to" address. If `to` is None then compute contract adddress + pub fn to_or_contract_addr(&self) -> Address { + self.to + .unwrap_or_else(|| get_contract_address(self.from, self.nonce)) + } + /// Determine if this transaction is a contract create transaction + pub fn is_create(&self) -> bool { + self.to.is_none() + } + + /// Convert to transaction response + pub fn to_response( + &self, + transaction_index: U64, + chain_id: Word, + block_number: U64, + ) -> response::Transaction { + response::Transaction { + from: self.from, + to: self.to, + value: self.value, + input: self.call_data.clone(), + gas_price: Some(self.gas_price), + access_list: self.access_list.clone(), + nonce: self.nonce, + gas: self.gas_limit, + transaction_index: Some(transaction_index), + r: self.r, + s: self.s, + v: U64::from(self.v), + block_number: Some(block_number), + chain_id: Some(chain_id), + ..response::Transaction::default() + } + } } /// GethData is a type that contains all the information of a Ethereum block diff --git a/testool/src/statetest/executor.rs b/testool/src/statetest/executor.rs index 1b110f6062..7a978934dc 100644 --- a/testool/src/statetest/executor.rs +++ b/testool/src/statetest/executor.rs @@ -144,7 +144,7 @@ fn into_traceconfig(st: StateTest) -> (String, TraceConfig, StateTestResult) { to: st.to, nonce: st.nonce, value: st.value, - gas_limit: U256::from(st.gas_limit), + gas_limit: st.gas_limit.into(), gas_price: st.gas_price, gas_fee_cap: U256::zero(), gas_tip_cap: U256::zero(), @@ -212,22 +212,12 @@ pub fn run_test( .transactions .into_iter() .enumerate() - .map(|(index, tx)| eth_types::Transaction { - from: tx.from, - to: tx.to, - value: tx.value, - input: tx.call_data, - gas_price: Some(tx.gas_price), - access_list: tx.access_list, - nonce: tx.nonce, - gas: tx.gas_limit, - transaction_index: Some(U64::from(index)), - r: tx.r, - s: tx.s, - v: U64::from(tx.v), - block_number: Some(U64::from(trace_config.block_constants.number.as_u64())), - chain_id: Some(trace_config.chain_id), - ..eth_types::Transaction::default() + .map(|(index, tx)| { + tx.to_response( + U64::from(index), + trace_config.chain_id, + trace_config.block_constants.number, + ) }) .collect(); diff --git a/zkevm-circuits/src/evm_circuit/execution/address.rs b/zkevm-circuits/src/evm_circuit/execution/address.rs index 508cabcd61..f663d87e88 100644 --- a/zkevm-circuits/src/evm_circuit/execution/address.rs +++ b/zkevm-circuits/src/evm_circuit/execution/address.rs @@ -71,7 +71,7 @@ impl ExecutionGadget for AddressGadget { self.same_context.assign_exec_step(region, offset, step)?; let address = block.rws[step.rw_indices[1]].stack_value(); - debug_assert_eq!(call.callee_address, address.to_address()); + debug_assert_eq!(call.address, address.to_address()); self.address.assign( region, diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index f875c83f48..c4b0642609 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -1,5 +1,5 @@ use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId}; -use eth_types::{evm_types::GasCost, Field, ToScalar}; +use eth_types::{evm_types::GasCost, Field, ToScalar, ToWord}; use halo2_proofs::{circuit::Value, plonk::Error}; use crate::{ @@ -156,7 +156,7 @@ impl ExecutionGadget for CodeCopyGadget { let bytecode = block .bytecodes - .get(&call.code_hash) + .get(&call.code_hash.to_word()) .expect("could not find current environment's bytecode"); let code_size = bytecode.bytes.len() as u64; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index 11c95302a8..72e0767dd8 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -13,7 +13,7 @@ use crate::{ }, util::Expr, }; -use eth_types::{evm_types::OpcodeId, Field, U256}; +use eth_types::{evm_types::OpcodeId, Field, ToWord, U256}; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -126,7 +126,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { let code = block .bytecodes - .get(&call.code_hash) + .get(&call.code_hash.to_word()) .expect("could not find current environment's bytecode"); let code_len = code.bytes.len() as u64; self.code_len diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs index 8a0002e2e2..ac00733760 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs @@ -194,7 +194,7 @@ impl ExecutionGadget for ErrorOOGSloadSstoreGadget { region, offset, Value::known( - call.callee_address + call.address .to_scalar() .expect("unexpected Address -> Scalar conversion failure"), ), diff --git a/zkevm-circuits/src/evm_circuit/execution/logs.rs b/zkevm-circuits/src/evm_circuit/execution/logs.rs index d3d0fe2ca4..a2be9af931 100644 --- a/zkevm-circuits/src/evm_circuit/execution/logs.rs +++ b/zkevm-circuits/src/evm_circuit/execution/logs.rs @@ -233,7 +233,7 @@ impl ExecutionGadget for LogGadget { region, offset, Value::known( - call.callee_address + call.address .to_scalar() .expect("unexpected Address -> Scalar conversion failure"), ), diff --git a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs index 9c20e3ee1e..20308cb23c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs +++ b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs @@ -256,7 +256,7 @@ impl ExecutionGadget for ReturnRevertGadget { self.is_success .assign(region, offset, Value::known(call.is_success.into()))?; - if !call.is_root && !call.is_create { + if !call.is_root && !call.is_create() { for (cell, value) in [ (&self.return_data_length, call.return_data_length.into()), (&self.return_data_offset, call.return_data_offset.into()), @@ -272,7 +272,7 @@ impl ExecutionGadget for ReturnRevertGadget { )?; } - if call.is_create && call.is_success { + if call.is_create() && call.is_success { let values: Vec<_> = (3..3 + length.as_usize()) .map(|i| block.rws[step.rw_indices[i]].memory_value()) .collect(); @@ -285,7 +285,7 @@ impl ExecutionGadget for ReturnRevertGadget { )?; } - let copy_rw_increase = if call.is_create && call.is_success { + let copy_rw_increase = if call.is_create() && call.is_success { length.as_u64() } else if !call.is_root { 2 * std::cmp::min(call.return_data_length, length.as_u64()) @@ -297,7 +297,7 @@ impl ExecutionGadget for ReturnRevertGadget { self.copy_rw_increase_is_zero .assign(region, offset, F::from(copy_rw_increase))?; - let is_contract_deployment = call.is_create && call.is_success && !length.is_zero(); + let is_contract_deployment = call.is_create() && call.is_success && !length.is_zero(); if !call.is_root { let rw_counter_offset = 3 + if is_contract_deployment { 5 + length.as_u64() @@ -323,7 +323,7 @@ impl ExecutionGadget for ReturnRevertGadget { self.address.assign( region, offset, - Value::known(call.callee_address.to_scalar().unwrap()), + Value::known(call.address.to_scalar().unwrap()), )?; self.reversion_info.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs index 584fcee949..9d0f938bb0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs @@ -72,7 +72,7 @@ impl ExecutionGadget for SelfbalanceGadget { region, offset, Value::known( - call.callee_address + call.address .to_scalar() .expect("unexpected Address -> Scalar conversion failure"), ), diff --git a/zkevm-circuits/src/evm_circuit/execution/sload.rs b/zkevm-circuits/src/evm_circuit/execution/sload.rs index 9d3f623909..da64916ac1 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sload.rs @@ -112,7 +112,7 @@ impl ExecutionGadget for SloadGadget { region, offset, Value::known( - call.callee_address + call.address .to_scalar() .expect("unexpected Address -> Scalar conversion failure"), ), diff --git a/zkevm-circuits/src/evm_circuit/execution/sstore.rs b/zkevm-circuits/src/evm_circuit/execution/sstore.rs index 7446e17938..dcc8468dc9 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sstore.rs @@ -178,7 +178,7 @@ impl ExecutionGadget for SstoreGadget { region, offset, Value::known( - call.callee_address + call.address .to_scalar() .expect("unexpected Address -> Scalar conversion failure"), ), diff --git a/zkevm-circuits/src/evm_circuit/execution/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index 9045ca94ac..b79d6dc906 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -17,7 +17,7 @@ use crate::{ util::Expr, }; use bus_mapping::evm::OpcodeId; -use eth_types::Field; +use eth_types::{Field, ToWord}; use halo2_proofs::{circuit::Value, plonk::Error}; #[derive(Clone, Debug)] @@ -105,7 +105,7 @@ impl ExecutionGadget for StopGadget { ) -> Result<(), Error> { let code = block .bytecodes - .get(&call.code_hash) + .get(&call.code_hash.to_word()) .expect("could not find current environment's bytecode"); self.code_length.assign( region, diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index 8c83044bb3..b0f8fb6b60 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -8,6 +8,7 @@ use crate::{ util::Expr, }; use bus_mapping::evm::OpcodeId; +use eth_types::ToWord; use halo2_proofs::{ arithmetic::FieldExt, circuit::Value, @@ -561,18 +562,16 @@ impl Step { )?; self.state .call_id - .assign(region, offset, Value::known(F::from(call.id as u64)))?; + .assign(region, offset, Value::known(F::from(call.call_id as u64)))?; self.state .is_root .assign(region, offset, Value::known(F::from(call.is_root as u64)))?; - self.state.is_create.assign( - region, - offset, - Value::known(F::from(call.is_create as u64)), - )?; + self.state + .is_create + .assign(region, offset, Value::known(F::from(call.is_create())))?; self.state .code_hash - .assign(region, offset, region.word_rlc(call.code_hash))?; + .assign(region, offset, region.word_rlc(call.code_hash.to_word()))?; self.state.program_counter.assign( region, offset, diff --git a/zkevm-circuits/src/pi_circuit.rs b/zkevm-circuits/src/pi_circuit.rs index 89222c7c2d..22951d60dc 100644 --- a/zkevm-circuits/src/pi_circuit.rs +++ b/zkevm-circuits/src/pi_circuit.rs @@ -58,7 +58,7 @@ pub struct TxValues { gas_price: Word, from_addr: Address, to_addr: Address, - is_create: u64, + is_create: bool, value: Word, call_data_len: u64, call_data_gas_cost: u64, @@ -145,17 +145,11 @@ impl PublicData { gas_price: tx.gas_price, gas: tx.gas_limit, from_addr: tx.from, - to_addr: tx.to.unwrap_or_else(Address::zero), - is_create: (tx.to.is_none() as u64), + to_addr: tx.to_or_zero(), + is_create: tx.is_create(), value: tx.value, - call_data_len: tx.call_data.0.len() as u64, - call_data_gas_cost: tx.call_data.0.iter().fold(0, |acc, byte| { - acc + if *byte == 0 { - ZERO_BYTE_GAS_COST - } else { - NONZERO_BYTE_GAS_COST - } - }), + call_data_len: tx.call_data.len() as u64, + call_data_gas_cost: tx.call_data_gas_cost(), tx_sign_hash: msg_hash_le, }); } diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index 1f2ca3e9eb..a21987bcbb 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -18,9 +18,7 @@ use crate::{ util::{random_linear_combine_word as rlc, Challenges, SubCircuit, SubCircuitConfig}, witness, }; -use eth_types::{ - geth_types::Transaction, sign_types::SignData, Address, Field, ToLittleEndian, ToScalar, -}; +use eth_types::{geth_types::Transaction, sign_types::SignData, Field, ToLittleEndian, ToScalar}; use halo2_proofs::{ circuit::{AssignedCell, Layouter, Region, Value}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed}, @@ -204,12 +202,7 @@ impl TxCircuit { }; for (tag, value) in [ - ( - TxFieldTag::Nonce, - challenges - .evm_word() - .map(|challenge| rlc(tx.nonce.to_le_bytes(), challenge)), - ), + (TxFieldTag::Nonce, Value::known(F::from(tx.nonce.as_u64()))), ( TxFieldTag::Gas, Value::known(F::from(tx.gas_limit.as_u64())), @@ -226,17 +219,9 @@ impl TxCircuit { ), ( TxFieldTag::CalleeAddress, - Value::known( - tx.to - .unwrap_or_else(Address::zero) - .to_scalar() - .expect("tx.to too big"), - ), - ), - ( - TxFieldTag::IsCreate, - Value::known(F::from(tx.to.is_none() as u64)), + Value::known(tx.to_or_zero().to_scalar().expect("tx.to too big")), ), + (TxFieldTag::IsCreate, Value::known(F::from(tx.is_create()))), ( TxFieldTag::Value, challenges @@ -249,12 +234,7 @@ impl TxCircuit { ), ( TxFieldTag::CallDataGasCost, - Value::known(F::from( - tx.call_data - .0 - .iter() - .fold(0, |acc, byte| acc + if *byte == 0 { 4 } else { 16 }), - )), + Value::known(F::from(tx.call_data_gas_cost())), ), ( TxFieldTag::TxSignHash, diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index 22bca9affd..019706ad0e 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -6,8 +6,6 @@ mod block; pub use block::{block_convert, Block, BlockContext}; mod bytecode; pub use bytecode::Bytecode; -mod call; -pub use call::Call; mod mpt; pub use mpt::{MptUpdate, MptUpdateRow, MptUpdates}; mod rw; @@ -15,4 +13,5 @@ pub use rw::{Rw, RwMap, RwRow}; mod step; pub use step::ExecStep; mod tx; +pub use bus_mapping::circuit_input_builder::Call; pub use tx::Transaction; diff --git a/zkevm-circuits/src/witness/call.rs b/zkevm-circuits/src/witness/call.rs deleted file mode 100644 index c3161721b0..0000000000 --- a/zkevm-circuits/src/witness/call.rs +++ /dev/null @@ -1,42 +0,0 @@ -use eth_types::{Address, Word}; - -/// Call in transactions. -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct Call { - /// The unique identifier of call in the whole proof, using the - /// `rw_counter` at the call step. - pub id: usize, - /// Indicate if the call is the root call - pub is_root: bool, - /// Indicate if the call is a create call - pub is_create: bool, - /// The identifier of current executed bytecode - pub code_hash: Word, - /// The `rw_counter` at the end of reversion of a call if it has - /// `is_persistent == false` - pub rw_counter_end_of_reversion: usize, - /// The call index of caller - pub caller_id: usize, - /// The depth in the call stack - pub depth: usize, - /// The caller address - pub caller_address: Address, - /// The callee address - pub callee_address: Address, - /// The call data offset in the memory - pub call_data_offset: u64, - /// The length of call data - pub call_data_length: u64, - /// The return data offset in the memory - pub return_data_offset: u64, - /// The length of return data - pub return_data_length: u64, - /// The ether amount of the transaction - pub value: Word, - /// Indicate if this call halts successfully. - pub is_success: bool, - /// Indicate if this call and all its caller have `is_success == true` - pub is_persistent: bool, - /// Indicate if it's a static call - pub is_static: bool, -} diff --git a/zkevm-circuits/src/witness/tx.rs b/zkevm-circuits/src/witness/tx.rs index 60f514e123..9c0475cce6 100644 --- a/zkevm-circuits/src/witness/tx.rs +++ b/zkevm-circuits/src/witness/tx.rs @@ -1,5 +1,5 @@ use bus_mapping::circuit_input_builder; -use eth_types::{Address, Field, ToLittleEndian, ToScalar, ToWord, Word}; +use eth_types::{Address, Field, ToLittleEndian, ToScalar, Word}; use halo2_proofs::circuit::Value; use crate::{evm_circuit::util::rlc, table::TxContextFieldTag, util::Challenges}; @@ -124,42 +124,17 @@ impl Transaction { pub(super) fn tx_convert(tx: &circuit_input_builder::Transaction, id: usize) -> Transaction { Transaction { id, - nonce: tx.nonce, - gas: tx.gas, - gas_price: tx.gas_price, - caller_address: tx.from, - callee_address: tx.to, + nonce: tx.tx.nonce.as_u64(), + gas: tx.gas(), + gas_price: tx.tx.gas_price, + caller_address: tx.tx.from, + callee_address: tx.tx.to_or_contract_addr(), is_create: tx.is_create(), - value: tx.value, - call_data: tx.input.clone(), - call_data_length: tx.input.len(), - call_data_gas_cost: tx - .input - .iter() - .fold(0, |acc, byte| acc + if *byte == 0 { 4 } else { 16 }), - calls: tx - .calls() - .iter() - .map(|call| Call { - id: call.call_id, - is_root: call.is_root, - is_create: call.is_create(), - code_hash: call.code_hash.to_word(), - rw_counter_end_of_reversion: call.rw_counter_end_of_reversion, - caller_id: call.caller_id, - depth: call.depth, - caller_address: call.caller_address, - callee_address: call.address, - call_data_offset: call.call_data_offset, - call_data_length: call.call_data_length, - return_data_offset: call.return_data_offset, - return_data_length: call.return_data_length, - value: call.value, - is_success: call.is_success, - is_persistent: call.is_persistent, - is_static: call.is_static, - }) - .collect(), + value: tx.tx.value, + call_data: tx.tx.call_data.to_vec(), + call_data_length: tx.tx.call_data.len(), + call_data_gas_cost: tx.tx.call_data_gas_cost(), + calls: tx.calls().to_vec(), steps: tx.steps().iter().map(step_convert).collect(), } } From 37b8aca374e0d706e7cef6597a89e6e367ec6da0 Mon Sep 17 00:00:00 2001 From: naure Date: Thu, 4 May 2023 10:19:02 +0200 Subject: [PATCH 027/102] zellic-fix-1: fix typo in multiplied terms (#1389) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Description An important typo. ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) ### Contents - Add term `a[3] * b[1]` (was written as `b[2]`). Co-authored-by: Aurélien Nicolas --- gadgets/src/mul_add.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gadgets/src/mul_add.rs b/gadgets/src/mul_add.rs index 353c84fdac..7ab7a6e211 100644 --- a/gadgets/src/mul_add.rs +++ b/gadgets/src/mul_add.rs @@ -158,8 +158,8 @@ impl MulAddChip { overflow = carry_hi_expr.clone() + a_limbs[1].clone() * b_limbs[3].clone() + a_limbs[2].clone() * b_limbs[2].clone() - + a_limbs[3].clone() * b_limbs[2].clone() + a_limbs[2].clone() * b_limbs[3].clone() + + a_limbs[3].clone() * b_limbs[1].clone() + a_limbs[3].clone() * b_limbs[2].clone() + a_limbs[3].clone() * b_limbs[3].clone(); From b8ae7af639af035a6ad5081716012ee2ea48e7cb Mon Sep 17 00:00:00 2001 From: Eduard S Date: Thu, 4 May 2023 16:35:02 +0200 Subject: [PATCH 028/102] Update halo2 dependency to v2023_04_20 (#1374) ### Description Update halo2 to the latest dependency, which contains some changes affecting the `ff` trait. ### Issue Link Resolve #1366 ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Rationale I've extended the `Field` trait we define in `eth_types` to contain the common traits used in different places, to avoid having a custom list of traits in each function. --- Cargo.lock | 89 +++++++++---------- Cargo.toml | 2 +- bus-mapping/Cargo.toml | 2 +- circuit-benchmarks/Cargo.toml | 2 +- eth-types/Cargo.toml | 2 +- eth-types/src/lib.rs | 32 +++++-- eth-types/src/sign_types.rs | 14 +-- gadgets/Cargo.toml | 2 +- gadgets/src/batched_is_zero.rs | 14 ++- gadgets/src/binary_number.rs | 2 +- gadgets/src/evm_word.rs | 8 +- gadgets/src/is_zero.rs | 2 +- gadgets/src/less_than.rs | 12 ++- gadgets/src/monotone.rs | 25 +++--- gadgets/src/mul_add.rs | 10 +-- gadgets/src/util.rs | 87 +++++++++--------- integration-tests/Cargo.toml | 2 +- keccak256/src/arith_helpers.rs | 2 +- keccak256/src/keccak_arith.rs | 5 +- testool/Cargo.toml | 2 +- zkevm-circuits/Cargo.toml | 12 +-- .../src/bytecode_circuit/bytecode_unroller.rs | 4 +- .../src/bytecode_circuit/circuit.rs | 24 ++--- zkevm-circuits/src/bytecode_circuit/test.rs | 20 ++--- zkevm-circuits/src/copy_circuit.rs | 30 +++---- zkevm-circuits/src/evm_circuit.rs | 2 +- zkevm-circuits/src/evm_circuit/execution.rs | 17 ++-- .../src/evm_circuit/execution/balance.rs | 2 +- .../src/evm_circuit/execution/begin_tx.rs | 2 +- .../src/evm_circuit/execution/comparator.rs | 2 +- .../src/evm_circuit/execution/end_tx.rs | 2 +- .../execution/error_oog_static_memory.rs | 6 +- .../src/evm_circuit/execution/exp.rs | 2 +- .../src/evm_circuit/execution/extcodesize.rs | 2 +- .../src/evm_circuit/execution/logs.rs | 4 +- .../src/evm_circuit/execution/memory.rs | 2 +- .../evm_circuit/execution/return_revert.rs | 7 +- .../execution/signed_comparator.rs | 2 +- .../src/evm_circuit/execution/signextend.rs | 2 +- zkevm-circuits/src/evm_circuit/step.rs | 23 +++-- zkevm-circuits/src/evm_circuit/table.rs | 24 ++--- zkevm-circuits/src/evm_circuit/util.rs | 59 ++++++------ .../src/evm_circuit/util/instrumentation.rs | 4 +- .../util/math_gadget/batched_is_zero.rs | 4 +- .../evm_circuit/util/math_gadget/byte_size.rs | 4 +- .../evm_circuit/util/math_gadget/is_zero.rs | 6 +- .../src/evm_circuit/util/math_gadget/lt.rs | 6 +- .../util/math_gadget/pair_select.rs | 4 +- .../src/evm_circuit/util/math_gadget/rlp.rs | 4 +- .../evm_circuit/util/math_gadget/test_util.rs | 4 +- .../src/evm_circuit/util/memory_gadget.rs | 2 +- zkevm-circuits/src/exp_circuit.rs | 8 +- zkevm-circuits/src/keccak_circuit.rs | 20 +++-- .../src/keccak_circuit/cell_manager.rs | 10 +-- .../src/keccak_circuit/keccak_packed_multi.rs | 29 +++--- zkevm-circuits/src/keccak_circuit/util.rs | 10 +-- zkevm-circuits/src/pi_circuit.rs | 64 ++++++------- zkevm-circuits/src/root_circuit.rs | 13 ++- .../src/root_circuit/aggregation.rs | 42 +++++---- zkevm-circuits/src/state_circuit.rs | 11 +-- .../src/state_circuit/constraint_builder.rs | 2 +- .../state_circuit/lexicographic_ordering.rs | 2 +- zkevm-circuits/src/state_circuit/test.rs | 22 +++-- zkevm-circuits/src/super_circuit.rs | 2 +- zkevm-circuits/src/table.rs | 61 +++++++------ zkevm-circuits/src/tx_circuit.rs | 9 +- zkevm-circuits/src/tx_circuit/sign_verify.rs | 39 ++++---- zkevm-circuits/src/util.rs | 11 ++- zkevm-circuits/src/witness/block.rs | 19 ++-- zkevm-circuits/src/witness/bytecode.rs | 4 +- zkevm-circuits/src/witness/mpt.rs | 2 +- zkevm-circuits/src/witness/rw.rs | 10 +-- zkevm-circuits/src/witness/tx.rs | 18 ++-- 73 files changed, 518 insertions(+), 494 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db1af7910f..8c80f9102a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1262,9 +1262,8 @@ dependencies = [ [[package]] name = "ecc" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_04_20#f72db265aa3cebe297c9b9816e940d0e1d400886" dependencies = [ - "group 0.12.1", "integer", "num-bigint", "num-integer", @@ -1276,10 +1275,9 @@ dependencies = [ [[package]] name = "ecdsa" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_04_20#f72db265aa3cebe297c9b9816e940d0e1d400886" dependencies = [ "ecc", - "group 0.12.1", "num-bigint", "num-integer", "num-traits", @@ -1776,6 +1774,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ + "bitvec 1.0.1", "rand_core", "subtle", ] @@ -2166,7 +2165,7 @@ dependencies = [ "blake2b_simd", "ff 0.12.1", "group 0.12.1", - "pasta_curves", + "pasta_curves 0.4.1", "plotters", "rand_core", "rayon", @@ -2176,12 +2175,13 @@ dependencies = [ [[package]] name = "halo2_proofs" version = "0.2.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02#0a8646b78286a13d320759b1c585262d6536dce4" +source = "git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_04_20#be955686f86eb618f55d2320c0e042485b313d22" dependencies = [ "blake2b_simd", - "ff 0.12.1", - "group 0.12.1", - "halo2curves 0.3.1", + "ff 0.13.0", + "group 0.13.0", + "halo2curves", + "rand_chacha", "rand_core", "rayon", "sha3 0.9.1", @@ -2190,32 +2190,16 @@ dependencies = [ [[package]] name = "halo2curves" -version = "0.2.1" -source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.0#83c72d49762343ffc9576ca11a2aa615efe1029b" -dependencies = [ - "ff 0.12.1", - "group 0.12.1", - "lazy_static", - "num-bigint", - "num-traits", - "pasta_curves", - "rand", - "rand_core", - "static_assertions", - "subtle", -] - -[[package]] -name = "halo2curves" -version = "0.3.1" -source = "git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1#9b67e19bca30a35208b0c1b41c1723771e2c9f49" +version = "0.3.2" +source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.2#9f5c50810bbefe779ee5cf1d852b2fe85dc35d5e" dependencies = [ - "ff 0.12.1", - "group 0.12.1", + "ff 0.13.0", + "group 0.13.0", "lazy_static", "num-bigint", "num-traits", - "pasta_curves", + "pasta_curves 0.5.1", + "paste", "rand", "rand_core", "static_assertions", @@ -2225,9 +2209,8 @@ dependencies = [ [[package]] name = "halo2wrong" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_04_20#f72db265aa3cebe297c9b9816e940d0e1d400886" dependencies = [ - "group 0.12.1", "halo2_proofs 0.2.0", "num-bigint", "num-integer", @@ -2551,9 +2534,8 @@ dependencies = [ [[package]] name = "integer" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_04_20#f72db265aa3cebe297c9b9816e940d0e1d400886" dependencies = [ - "group 0.12.1", "maingate", "num-bigint", "num-integer", @@ -2703,15 +2685,15 @@ dependencies = [ [[package]] name = "lalrpop" -version = "0.19.8" +version = "0.19.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" +checksum = "f34313ec00c2eb5c3c87ca6732ea02dcf3af99c3ff7a8fb622ffb99c9d860a87" dependencies = [ "ascii-canvas", - "atty", "bit-set", "diff", "ena", + "is-terminal", "itertools", "lalrpop-util", "petgraph", @@ -2726,9 +2708,9 @@ dependencies = [ [[package]] name = "lalrpop-util" -version = "0.19.8" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" +checksum = "3d3b45d694c8074f77bc24fc26e47633c862a9cd3b48dd51209c02ba4c434d68" dependencies = [ "regex", ] @@ -2849,9 +2831,8 @@ dependencies = [ [[package]] name = "maingate" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_04_20#f72db265aa3cebe297c9b9816e940d0e1d400886" dependencies = [ - "group 0.12.1", "halo2wrong", "num-bigint", "num-integer", @@ -3177,6 +3158,21 @@ dependencies = [ "subtle", ] +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff 0.13.0", + "group 0.13.0", + "lazy_static", + "rand", + "static_assertions", + "subtle", +] + [[package]] name = "paste" version = "1.0.11" @@ -3458,10 +3454,9 @@ dependencies = [ [[package]] name = "poseidon" version = "0.2.0" -source = "git+https://github.com/privacy-scaling-explorations/poseidon.git?tag=v2022_10_22#5d29df01a95e3df6334080d28e983407f56b5da3" +source = "git+https://github.com/privacy-scaling-explorations/poseidon.git?tag=v2023_04_20#807f8f555313f726ca03bdf941f798098f488ba4" dependencies = [ - "group 0.12.1", - "halo2curves 0.2.1", + "halo2curves", "subtle", ] @@ -4362,11 +4357,11 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "snark-verifier" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/snark-verifier?tag=v2023_02_02#df03d898b841f71cbc36c2fb9fa07b8196f9623e" +source = "git+https://github.com/privacy-scaling-explorations/snark-verifier?tag=v2023_04_20#e5d5e4a6ccff2bba71baf77ab7a12b124d6364a1" dependencies = [ "ecc", "halo2_proofs 0.2.0", - "halo2curves 0.3.1", + "halo2curves", "hex", "itertools", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 100836d5ce..be096fc2fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ ] [patch.crates-io] -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } # Definition of benchmarks profile to use. [profile.bench] diff --git a/bus-mapping/Cargo.toml b/bus-mapping/Cargo.toml index a60f1daab9..00204bf9b5 100644 --- a/bus-mapping/Cargo.toml +++ b/bus-mapping/Cargo.toml @@ -13,7 +13,7 @@ mock = { path = "../mock", optional = true } ethers-core = "0.17.0" ethers-providers = "0.17.0" -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } itertools = "0.10" lazy_static = "1.4" log = "0.4.14" diff --git a/circuit-benchmarks/Cargo.toml b/circuit-benchmarks/Cargo.toml index 222db7931d..58ee36a853 100644 --- a/circuit-benchmarks/Cargo.toml +++ b/circuit-benchmarks/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } ark-std = { version = "0.3", features = ["print-trace"] } zkevm-circuits = { path = "../zkevm-circuits", features = ["test"]} keccak256 = { path = "../keccak256" } diff --git a/eth-types/Cargo.toml b/eth-types/Cargo.toml index 078c1fee99..d0d43f8cfc 100644 --- a/eth-types/Cargo.toml +++ b/eth-types/Cargo.toml @@ -10,7 +10,7 @@ ethers-core = "0.17.0" ethers-signers = "0.17.0" hex = "0.4" lazy_static = "1.4" -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } regex = "1.5.4" serde = {version = "1.0.130", features = ["derive"] } serde_json = "1.0.66" diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index ab40c488e0..bbe3ab9eb1 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -24,12 +24,9 @@ pub mod sign_types; pub use bytecode::Bytecode; pub use error::Error; -use halo2_proofs::{ - arithmetic::{Field as Halo2Field, FieldExt}, - halo2curves::{ - bn256::{Fq, Fr}, - group::ff::PrimeField, - }, +use halo2_proofs::halo2curves::{ + bn256::{Fq, Fr}, + ff::{Field as Halo2Field, FromUniformBytes, PrimeField}, }; use crate::evm_types::{ @@ -47,9 +44,28 @@ pub use ethers_core::{ use serde::{de, Deserialize, Serialize}; use std::{collections::HashMap, fmt, str::FromStr}; -/// Trait used to reduce verbosity with the declaration of the [`FieldExt`] +/// Trait used to reduce verbosity with the declaration of the [`PrimeField`] /// trait and its repr. -pub trait Field: FieldExt + Halo2Field + PrimeField {} +pub trait Field: Halo2Field + PrimeField + FromUniformBytes<64> + Ord { + /// Gets the lower 128 bits of this field element when expressed + /// canonically. + fn get_lower_128(&self) -> u128 { + let bytes = self.to_repr(); + bytes[..16] + .iter() + .rev() + .fold(0u128, |acc, value| acc * 256u128 + *value as u128) + } + /// Gets the lower 32 bits of this field element when expressed + /// canonically. + fn get_lower_32(&self) -> u32 { + let bytes = self.to_repr(); + bytes[..4] + .iter() + .rev() + .fold(0u32, |acc, value| acc * 256u32 + *value as u32) + } +} // Impl custom `Field` trait for BN256 Fr to be used and consistent with the // rest of the workspace. diff --git a/eth-types/src/sign_types.rs b/eth-types/src/sign_types.rs index f6bee6980b..49df1b1531 100644 --- a/eth-types/src/sign_types.rs +++ b/eth-types/src/sign_types.rs @@ -2,10 +2,10 @@ use crate::{ToBigEndian, Word}; use halo2_proofs::{ - arithmetic::{CurveAffine, FieldExt}, + arithmetic::{CurveAffine, Field}, halo2curves::{ group::{ - ff::{Field as GroupField, PrimeField}, + ff::{FromUniformBytes, PrimeField}, Curve, }, secp256k1::{self, Secp256k1Affine}, @@ -36,7 +36,7 @@ pub fn sign( let mut x_bytes = [0u8; 64]; x_bytes[..32].copy_from_slice(&x_repr[..]); - let sig_r = secp256k1::Fq::from_bytes_wide(&x_bytes); // get x cordinate (E::Base) on E::Scalar + let sig_r = secp256k1::Fq::from_uniform_bytes(&x_bytes); // get x cordinate (E::Base) on E::Scalar let sig_s = randomness_inv * (msg_hash + sig_r * sk); (sig_r, sig_s) } @@ -56,11 +56,11 @@ pub struct SignData { lazy_static! { static ref SIGN_DATA_DEFAULT: SignData = { let generator = Secp256k1Affine::generator(); - let sk = secp256k1::Fq::one(); + let sk = secp256k1::Fq::ONE; let pk = generator * sk; let pk = pk.to_affine(); - let msg_hash = secp256k1::Fq::one(); - let randomness = secp256k1::Fq::one(); + let msg_hash = secp256k1::Fq::ONE; + let randomness = secp256k1::Fq::ONE; let (sig_r, sig_s) = sign(randomness, sk, msg_hash); SignData { @@ -123,7 +123,7 @@ pub fn recover_pk( lazy_static! { /// Secp256k1 Curve Scalar. Referece: Section 2.4.1 (parameter `n`) in "SEC 2: Recommended /// Elliptic Curve Domain Parameters" document at http://www.secg.org/sec2-v2.pdf - pub static ref SECP256K1_Q: BigUint = BigUint::from_bytes_le(&(secp256k1::Fq::zero() - secp256k1::Fq::one()).to_repr()) + 1u64; + pub static ref SECP256K1_Q: BigUint = BigUint::from_bytes_le(&(secp256k1::Fq::ZERO - secp256k1::Fq::ONE).to_repr()) + 1u64; } /// Helper function to convert a `CtOption` into an `Result`. Similar to diff --git a/gadgets/Cargo.toml b/gadgets/Cargo.toml index 1ae6a29100..be8bf9d550 100644 --- a/gadgets/Cargo.toml +++ b/gadgets/Cargo.toml @@ -6,7 +6,7 @@ authors = ["The appliedzkp team"] license = "MIT OR Apache-2.0" [dependencies] -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } sha3 = "0.7.2" eth-types = { path = "../eth-types" } digest = "0.7.6" diff --git a/gadgets/src/batched_is_zero.rs b/gadgets/src/batched_is_zero.rs index 8128477c28..2f3acb2c22 100644 --- a/gadgets/src/batched_is_zero.rs +++ b/gadgets/src/batched_is_zero.rs @@ -7,7 +7,6 @@ use eth_types::Field; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Region, Value}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Phase, VirtualCells}, poly::Rotation, @@ -48,7 +47,7 @@ pub struct BatchedIsZeroChip { _marker: PhantomData, } -impl BatchedIsZeroChip { +impl BatchedIsZeroChip { /// Configure the BatchedIsZeroChip pub fn configure( meta: &mut ConstraintSystem, @@ -100,9 +99,9 @@ impl BatchedIsZeroChip { .iter() .find_map(|value| Option::::from(value.invert())) { - (F::zero(), inverse) + (F::ZERO, inverse) } else { - (F::one(), F::zero()) + (F::ONE, F::ZERO) } }); @@ -134,7 +133,6 @@ impl BatchedIsZeroChip { mod test { use super::*; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, halo2curves::bn256::Fr, @@ -151,13 +149,13 @@ mod test { } #[derive(Default)] - struct TestCircuit { + struct TestCircuit { values: Option<[u64; N]>, expect_is_zero: Option, _marker: PhantomData, } - impl Circuit for TestCircuit { + impl Circuit for TestCircuit { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; @@ -218,7 +216,7 @@ mod test { || "expect_is_zero", config.expect_is_zero, 0, - || Value::known(F::from(*expect_is_zero)), + || Value::known(F::from(*expect_is_zero as u64)), )?; for (value_column, value) in config.values.iter().zip(values.iter()) { region.assign_advice( diff --git a/gadgets/src/binary_number.rs b/gadgets/src/binary_number.rs index 2005e09405..cb5099504b 100644 --- a/gadgets/src/binary_number.rs +++ b/gadgets/src/binary_number.rs @@ -190,7 +190,7 @@ where || format!("binary number {:?}", column), column, offset, - || Value::known(F::from(bit)), + || Value::known(F::from(bit as u64)), )?; } Ok(()) diff --git a/gadgets/src/evm_word.rs b/gadgets/src/evm_word.rs index e3fa344f88..16f85c70e3 100644 --- a/gadgets/src/evm_word.rs +++ b/gadgets/src/evm_word.rs @@ -28,12 +28,12 @@ pub fn r() -> F { } let mut r = [0; 64]; r[..32].copy_from_slice(hasher.fixed_result().as_slice()); - F::from_bytes_wide(&r) + F::from_uniform_bytes(&r) } /// Returns encoding of big-endian representation of a 256-bit word. pub fn encode(vals: impl Iterator, r: F) -> F { - vals.fold(F::zero(), |acc, val| { + vals.fold(F::ZERO, |acc, val| { let byte = F::from(val as u64); acc * r + byte }) @@ -73,7 +73,7 @@ impl WordConfig { byte_lookup: Column, ) -> Self { // Expression representing `encode(word)`. - let mut encode_word_expr = Expression::Constant(F::zero()); + let mut encode_word_expr = Expression::Constant(F::ZERO); // Lookup each byte in the witnessed word representation to // range-constrain it to 8 bits. @@ -254,7 +254,7 @@ mod tests { assert_eq!( prover.verify(), Err(vec![VerifyFailure::Lookup { - name: "Encoded word / Pub inputs", + name: "Encoded word / Pub inputs".to_string(), lookup_index: 32, location: FailureLocation::InRegion { region: halo2_proofs::dev::metadata::Region::from(( diff --git a/gadgets/src/is_zero.rs b/gadgets/src/is_zero.rs index 0f0d9fe721..cc6f3e3a67 100644 --- a/gadgets/src/is_zero.rs +++ b/gadgets/src/is_zero.rs @@ -115,7 +115,7 @@ impl IsZeroInstruction for IsZeroChip { value: Value, ) -> Result<(), Error> { let config = self.config(); - let value_invert = value.map(|value| value.invert().unwrap_or(F::zero())); + let value_invert = value.map(|value| value.invert().unwrap_or(F::ZERO)); region.assign_advice( || "witness inverse of value", config.value_inv, diff --git a/gadgets/src/less_than.rs b/gadgets/src/less_than.rs index 0b0fd525ca..db539af086 100644 --- a/gadgets/src/less_than.rs +++ b/gadgets/src/less_than.rs @@ -2,7 +2,6 @@ use eth_types::Field; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Chip, Layouter, Region, Value}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, poly::Rotation, @@ -14,7 +13,7 @@ use super::{ }; /// Instruction that the Lt chip needs to implement. -pub trait LtInstruction { +pub trait LtInstruction { /// Assign the lhs and rhs witnesses to the Lt chip's region. fn assign( &self, @@ -128,7 +127,7 @@ impl LtInstruction for LtChip { || Value::known(F::from(lt as u64)), )?; - let diff = (lhs - rhs) + (if lt { config.range } else { F::zero() }); + let diff = (lhs - rhs) + (if lt { config.range } else { F::ZERO }); let diff_bytes = diff.to_repr(); let diff_bytes = diff_bytes.as_ref(); for (idx, diff_column) in config.diff.iter().enumerate() { @@ -178,10 +177,9 @@ impl Chip for LtChip { #[cfg(test)] mod test { - use super::{LtChip, LtConfig, LtInstruction}; + use super::*; use eth_types::Field; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, halo2curves::bn256::Fr as Fp, @@ -235,7 +233,7 @@ mod test { } #[derive(Default)] - struct TestCircuit { + struct TestCircuit { values: Option>, // checks[i] = lt(values[i + 1], values[i]) checks: Option>, @@ -355,7 +353,7 @@ mod test { } #[derive(Default)] - struct TestCircuit { + struct TestCircuit { values: Option>, // checks[i] = lt(values[i].0 - values[i].1) checks: Option>, diff --git a/gadgets/src/monotone.rs b/gadgets/src/monotone.rs index 798beeb995..39d4b6cf64 100644 --- a/gadgets/src/monotone.rs +++ b/gadgets/src/monotone.rs @@ -2,8 +2,8 @@ //! Monotone gadget helps to check if an advice column is monotonically //! increasing within a range. With strict enabled, it disallows equality of two //! cell. +use eth_types::Field; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Chip, Layouter, Value}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, poly::Rotation, @@ -25,7 +25,7 @@ pub(crate) struct MonotoneChip +impl MonotoneChip { /// configure which column should be check. q_enable here as a fn is @@ -90,7 +90,7 @@ impl } } -impl Chip +impl Chip for MonotoneChip { type Config = MonotoneConfig; @@ -107,9 +107,8 @@ impl Chip #[cfg(test)] mod test { - use super::{MonotoneChip, MonotoneConfig, Value}; + use super::*; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Layouter, SimpleFloorPlanner}, dev::{ FailureLocation, MockProver, @@ -128,12 +127,12 @@ mod test { } #[derive(Default)] - struct TestCircuit { + struct TestCircuit { values: Option>, _marker: PhantomData, } - impl Circuit + impl Circuit for TestCircuit { type Config = TestCircuitConfig; @@ -231,7 +230,7 @@ mod test { vec![1, 2, 2, 4, 4], Err(vec![ Lookup { - name: "Range check", + name: "Range check".to_string(), lookup_index: 0, location: FailureLocation::InRegion { region: halo2_proofs::dev::metadata::Region::from((1, "witness")), @@ -239,7 +238,7 @@ mod test { }, }, Lookup { - name: "Range check", + name: "Range check".to_string(), lookup_index: 0, location: FailureLocation::InRegion { region: halo2_proofs::dev::metadata::Region::from((1, "witness")), @@ -252,7 +251,7 @@ mod test { try_test_circuit( vec![1, 2, 3, 4, 105], Err(vec![Lookup { - name: "Range check", + name: "Range check".to_string(), lookup_index: 0, location: FailureLocation::InRegion { region: halo2_proofs::dev::metadata::Region::from((1, "witness")), @@ -264,7 +263,7 @@ mod test { try_test_circuit( vec![1, 2, 3, 103, 4], Err(vec![Lookup { - name: "Range check", + name: "Range check".to_string(), lookup_index: 0, location: FailureLocation::InRegion { region: halo2_proofs::dev::metadata::Region::from((1, "witness")), @@ -287,7 +286,7 @@ mod test { try_test_circuit( vec![1, 2, 3, 4, 105], Err(vec![Lookup { - name: "Range check", + name: "Range check".to_string(), lookup_index: 0, location: FailureLocation::InRegion { region: halo2_proofs::dev::metadata::Region::from((1, "witness")), @@ -299,7 +298,7 @@ mod test { try_test_circuit( vec![1, 2, 3, 103, 4], Err(vec![Lookup { - name: "Range check", + name: "Range check".to_string(), lookup_index: 0, location: FailureLocation::InRegion { region: halo2_proofs::dev::metadata::Region::from((1, "witness")), diff --git a/gadgets/src/mul_add.rs b/gadgets/src/mul_add.rs index 7ab7a6e211..5433b8dd80 100644 --- a/gadgets/src/mul_add.rs +++ b/gadgets/src/mul_add.rs @@ -241,7 +241,7 @@ impl MulAddChip { || format!("unused col: {}", offset), self.config.col4, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // b limbs. @@ -266,7 +266,7 @@ impl MulAddChip { || format!("unused col {}", offset + 1), self.config.col4, offset + 1, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // c_lo, c_hi, d_lo, d_hi. @@ -298,7 +298,7 @@ impl MulAddChip { || format!("unused col: {}", offset + 2), self.config.col4, offset + 2, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // carry_lo. @@ -328,7 +328,7 @@ impl MulAddChip { || format!("unused col: {}", offset + 4), self.config.col4, offset + 4, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // carry_hi. @@ -358,7 +358,7 @@ impl MulAddChip { || format!("unused col: {}", offset + 6), self.config.col4, offset + 6, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; Ok(()) diff --git a/gadgets/src/util.rs b/gadgets/src/util.rs index 41db324778..e0bfcaa6f1 100644 --- a/gadgets/src/util.rs +++ b/gadgets/src/util.rs @@ -1,27 +1,28 @@ //! Utility traits, functions used in the crate. use eth_types::{ evm_types::{GasCost, OpcodeId}, - U256, + Field, U256, }; -use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; +use halo2_proofs::plonk::Expression; /// Returns the sum of the passed in cells pub mod sum { use crate::util::Expr; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use eth_types::Field; + use halo2_proofs::plonk::Expression; /// Returns an expression for the sum of the list of expressions. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { + pub fn expr, I: IntoIterator>(inputs: I) -> Expression { inputs .into_iter() .fold(0.expr(), |acc, input| acc + input.expr()) } /// Returns the sum of the given list of values within the field. - pub fn value(values: &[u8]) -> F { + pub fn value(values: &[u8]) -> F { values .iter() - .fold(F::zero(), |acc, value| acc + F::from(*value as u64)) + .fold(F::ZERO, |acc, value| acc + F::from(*value as u64)) } } @@ -29,19 +30,20 @@ pub mod sum { /// otherwise. Inputs need to be boolean pub mod and { use crate::util::Expr; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use eth_types::Field; + use halo2_proofs::plonk::Expression; /// Returns an expression that evaluates to 1 only if all the expressions in /// the given list are 1, else returns 0. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { + pub fn expr, I: IntoIterator>(inputs: I) -> Expression { inputs .into_iter() .fold(1.expr(), |acc, input| acc * input.expr()) } /// Returns the product of all given values. - pub fn value(inputs: Vec) -> F { - inputs.iter().fold(F::one(), |acc, input| acc * input) + pub fn value(inputs: Vec) -> F { + inputs.iter().fold(F::ONE, |acc, input| acc * input) } } @@ -50,16 +52,17 @@ pub mod and { pub mod or { use super::{and, not}; use crate::util::Expr; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use eth_types::Field; + use halo2_proofs::plonk::Expression; /// Returns an expression that evaluates to 1 if any expression in the given /// list is 1. Returns 0 if all the expressions were 0. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { + pub fn expr, I: IntoIterator>(inputs: I) -> Expression { not::expr(and::expr(inputs.into_iter().map(not::expr))) } /// Returns the value after passing all given values through the OR gate. - pub fn value(inputs: Vec) -> F { + pub fn value(inputs: Vec) -> F { not::value(and::value(inputs.into_iter().map(not::value).collect())) } } @@ -68,16 +71,17 @@ pub mod or { /// `b` needs to be boolean pub mod not { use crate::util::Expr; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use eth_types::Field; + use halo2_proofs::plonk::Expression; /// Returns an expression that represents the NOT of the given expression. - pub fn expr>(b: E) -> Expression { + pub fn expr>(b: E) -> Expression { 1.expr() - b.expr() } /// Returns a value that represents the NOT of the given value. - pub fn value(b: F) -> F { - F::one() - b + pub fn value(b: F) -> F { + F::ONE - b } } @@ -85,15 +89,16 @@ pub mod not { /// `a` and `b` needs to be boolean pub mod xor { use crate::util::Expr; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use eth_types::Field; + use halo2_proofs::plonk::Expression; /// Returns an expression that represents the XOR of the given expression. - pub fn expr>(a: E, b: E) -> Expression { + pub fn expr>(a: E, b: E) -> Expression { a.expr() + b.expr() - 2.expr() * a.expr() * b.expr() } /// Returns a value that represents the XOR of the given value. - pub fn value(a: F, b: F) -> F { + pub fn value(a: F, b: F) -> F { a + b - F::from(2u64) * a * b } } @@ -102,11 +107,12 @@ pub mod xor { /// `selector == 0`. `selector` needs to be boolean. pub mod select { use crate::util::Expr; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use eth_types::Field; + use halo2_proofs::plonk::Expression; /// Returns the `when_true` expression when the selector is true, else /// returns the `when_false` expression. - pub fn expr( + pub fn expr( selector: Expression, when_true: Expression, when_false: Expression, @@ -116,18 +122,18 @@ pub mod select { /// Returns the `when_true` value when the selector is true, else returns /// the `when_false` value. - pub fn value(selector: F, when_true: F, when_false: F) -> F { - selector * when_true + (F::one() - selector) * when_false + pub fn value(selector: F, when_true: F, when_false: F) -> F { + selector * when_true + (F::ONE - selector) * when_false } /// Returns the `when_true` word when selector is true, else returns the /// `when_false` word. - pub fn value_word( + pub fn value_word( selector: F, when_true: [u8; 32], when_false: [u8; 32], ) -> [u8; 32] { - if selector == F::one() { + if selector == F::ONE { when_true } else { when_false @@ -137,7 +143,7 @@ pub mod select { /// Trait that implements functionality to get a constant expression from /// commonly used types. -pub trait Expr { +pub trait Expr { /// Returns an expression for the type. fn expr(&self) -> Expression; } @@ -146,7 +152,7 @@ pub trait Expr { #[macro_export] macro_rules! impl_expr { ($type:ty) => { - impl $crate::util::Expr for $type { + impl $crate::util::Expr for $type { #[inline] fn expr(&self) -> Expression { Expression::Constant(F::from(*self as u64)) @@ -154,7 +160,7 @@ macro_rules! impl_expr { } }; ($type:ty, $method:path) => { - impl $crate::util::Expr for $type { + impl $crate::util::Expr for $type { #[inline] fn expr(&self) -> Expression { Expression::Constant(F::from($method(self) as u64)) @@ -170,39 +176,34 @@ impl_expr!(usize); impl_expr!(OpcodeId, OpcodeId::as_u8); impl_expr!(GasCost, GasCost::as_u64); -impl Expr for Expression { +impl Expr for Expression { #[inline] fn expr(&self) -> Expression { self.clone() } } -impl Expr for &Expression { +impl Expr for &Expression { #[inline] fn expr(&self) -> Expression { (*self).clone() } } -impl Expr for i32 { +impl Expr for i32 { #[inline] fn expr(&self) -> Expression { Expression::Constant( - F::from(self.unsigned_abs() as u64) - * if self.is_negative() { - -F::one() - } else { - F::one() - }, + F::from(self.unsigned_abs() as u64) * if self.is_negative() { -F::ONE } else { F::ONE }, ) } } /// Given a bytes-representation of an expression, it computes and returns the /// single expression. -pub fn expr_from_bytes>(bytes: &[E]) -> Expression { +pub fn expr_from_bytes>(bytes: &[E]) -> Expression { let mut value = 0.expr(); - let mut multiplier = F::one(); + let mut multiplier = F::ONE; for byte in bytes.iter() { value = value + byte.expr() * multiplier; multiplier *= F::from(256); @@ -210,9 +211,9 @@ pub fn expr_from_bytes>(bytes: &[E]) -> Expression { value } -/// Returns 2**by as FieldExt -pub fn pow_of_two(by: usize) -> F { - F::from(2).pow(&[by as u64, 0, 0, 0]) +/// Returns 2**by as Field +pub fn pow_of_two(by: usize) -> F { + F::from(2).pow([by as u64, 0, 0, 0]) } /// Returns tuple consists of low and high part of U256 diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 3b02409e8e..67156dcecc 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -19,7 +19,7 @@ url = "2.2.2" pretty_assertions = "1.0.0" log = "0.4.14" env_logger = "0.9" -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } rand_chacha = "0.3" paste = "1.0" rand_xorshift = "0.3.0" diff --git a/keccak256/src/arith_helpers.rs b/keccak256/src/arith_helpers.rs index 9d223caea2..4877486b08 100644 --- a/keccak256/src/arith_helpers.rs +++ b/keccak256/src/arith_helpers.rs @@ -199,7 +199,7 @@ pub fn inspect(x: BigUint, name: &str, base: u8) { pub fn f_from_radix_be(buf: &[u8], base: u8) -> F { let base = F::from(base as u64); buf.iter() - .fold(F::zero(), |acc, &x| acc * base + F::from(x as u64)) + .fold(F::ZERO, |acc, &x| acc * base + F::from(x as u64)) } #[cfg(test)] diff --git a/keccak256/src/keccak_arith.rs b/keccak256/src/keccak_arith.rs index e04f8b720c..c59b0964f3 100644 --- a/keccak256/src/keccak_arith.rs +++ b/keccak256/src/keccak_arith.rs @@ -254,7 +254,10 @@ mod tests { convert_b13_lane_to_b9(BigUint::from(170u64), 0), BigUint::from(82u64) ); - assert_eq!(convert_b9_lane_to_b13(BigUint::from(82u64)), Zero::zero()); + assert_eq!( + convert_b9_lane_to_b13(BigUint::from(82u64)), + BigUint::zero() + ); assert_eq!(convert_b9_lane_to_b2(BigUint::from(82u64)), 0); assert_eq!( convert_b9_lane_to_b2(BigUint::from(9u64).pow(63) * 2u64), diff --git a/testool/Cargo.toml b/testool/Cargo.toml index a55df16161..5b4faed255 100644 --- a/testool/Cargo.toml +++ b/testool/Cargo.toml @@ -33,7 +33,7 @@ yaml-rust = "0.4.5" zkevm-circuits = { path="../zkevm-circuits", features=["test"] } rand_chacha = "0.3" rand = "0.8" -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } urlencoding = "2.1.2" diff --git a/zkevm-circuits/Cargo.toml b/zkevm-circuits/Cargo.toml index 17cf8a03fb..846dbc73c9 100644 --- a/zkevm-circuits/Cargo.toml +++ b/zkevm-circuits/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } num = "0.4" sha3 = "0.10" array-init = "2.0.0" @@ -27,15 +27,15 @@ lazy_static = "1.4" keccak256 = { path = "../keccak256"} log = "0.4" env_logger = "0.9" -ecdsa = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_02_02" } -ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_02_02" } -maingate = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_02_02" } -integer = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_02_02" } +ecdsa = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_04_20" } +ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_04_20" } +maingate = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_04_20" } +integer = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_04_20" } libsecp256k1 = "0.7" num-bigint = { version = "0.4" } subtle = "2.4" rand_chacha = "0.3" -snark-verifier = { git = "https://github.com/privacy-scaling-explorations/snark-verifier", tag = "v2023_02_02", default-features = false, features = ["loader_halo2", "system_halo2"] } +snark-verifier = { git = "https://github.com/privacy-scaling-explorations/snark-verifier", tag = "v2023_04_20", default-features = false, features = ["loader_halo2", "system_halo2"] } [dev-dependencies] bus-mapping = { path = "../bus-mapping", features = ["test"] } diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 299fa008b7..6c4fb174fc 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -28,8 +28,8 @@ pub fn unroll(bytes: Vec) -> UnrolledBytecode { let mut rows = vec![BytecodeRow:: { code_hash, tag: F::from(BytecodeFieldTag::Header as u64), - index: F::zero(), - is_code: F::zero(), + index: F::ZERO, + is_code: F::ZERO, value: F::from(bytes.len() as u64), }]; // Run over all the bytes diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index 8b6c19c7d0..cd70f56a42 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -516,7 +516,7 @@ impl BytecodeCircuitConfig { // Overwrite the witness assignment by using the values in the `overwrite` // parameter. This is used to explicitly set intermediate witness values for // negative tests. - let mut value_rlc = challenges.keccak_input().map(|_| F::zero()); + let mut value_rlc = challenges.keccak_input().map(|_| F::ZERO); for (offset, row) in overwrite.rows.iter().enumerate() { for (name, column, value) in [ ("tag", self.bytecode_table.tag, row.tag), @@ -533,14 +533,14 @@ impl BytecodeCircuitConfig { )?; } - if row.tag == F::one() { + if row.tag == F::ONE { value_rlc.as_mut().zip(challenges.keccak_input()).map( |(value_rlc, challenge)| { *value_rlc = *value_rlc * challenge + row.value }, ); } else { - value_rlc = challenges.keccak_input().map(|_| F::zero()); + value_rlc = challenges.keccak_input().map(|_| F::ZERO); } let code_hash = challenges @@ -580,7 +580,7 @@ impl BytecodeCircuitConfig { let mut push_data_left = 0; let mut next_push_data_left = 0; let mut push_data_size = 0; - let mut value_rlc = challenges.keccak_input().map(|_| F::zero()); + let mut value_rlc = challenges.keccak_input().map(|_| F::ZERO); let length = F::from(bytecode.bytes.len() as u64); // Code hash with challenge is calculated only using the first row of the @@ -689,13 +689,13 @@ impl BytecodeCircuitConfig { offset == last_row_offset, empty_hash, F::from(BytecodeFieldTag::Header as u64), - F::zero(), - F::zero(), - F::zero(), + F::ZERO, + F::ZERO, + F::ZERO, 0, - Value::known(F::zero()), - F::zero(), - F::zero(), + Value::known(F::ZERO), + F::ZERO, + F::ZERO, ) } @@ -735,7 +735,7 @@ impl BytecodeCircuitConfig { )?; // q_last - let q_last_value = if last { F::one() } else { F::zero() }; + let q_last_value = if last { F::ONE } else { F::ZERO }; region.assign_fixed( || format!("assign q_last {}", offset), self.q_last, @@ -785,7 +785,7 @@ impl BytecodeCircuitConfig { index_length_diff_is_zero_chip.assign( region, offset, - Value::known(index + F::one() - length), + Value::known(index + F::ONE - length), )?; Ok(()) diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 66555a15db..8ebed96b0b 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -6,7 +6,7 @@ use crate::{ }; use bus_mapping::evm::OpcodeId; use eth_types::{Bytecode, Field, Word}; -use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; +use halo2_proofs::{arithmetic::Field as Halo2Field, dev::MockProver, halo2curves::bn256::Fr}; use log::error; #[test] @@ -110,8 +110,8 @@ fn bytecode_unrolling() { BytecodeRow { code_hash, tag: Fr::from(BytecodeFieldTag::Header as u64), - index: Fr::zero(), - is_code: Fr::zero(), + index: Fr::ZERO, + is_code: Fr::ZERO, value: Fr::from(bytecode.to_vec().len() as u64), }, ); @@ -216,14 +216,14 @@ fn bytecode_invalid_index() { { let mut invalid = unrolled.clone(); for row in invalid.rows.iter_mut() { - row.index += Fr::one(); + row.index += Fr::ONE; } test_bytecode_circuit_unrolled::(k, vec![invalid], false); } // Don't increment an index once { let mut invalid = unrolled; - invalid.rows.last_mut().unwrap().index -= Fr::one(); + invalid.rows.last_mut().unwrap().index -= Fr::ONE; test_bytecode_circuit_unrolled::(k, vec![invalid], false); } } @@ -273,19 +273,19 @@ fn bytecode_invalid_is_code() { // Mark the 3rd byte as code (is push data from the first PUSH1) { let mut invalid = unrolled.clone(); - invalid.rows[3].is_code = Fr::one(); + invalid.rows[3].is_code = Fr::ONE; test_bytecode_circuit_unrolled::(k, vec![invalid], false); } // Mark the 4rd byte as data (is code) { let mut invalid = unrolled.clone(); - invalid.rows[4].is_code = Fr::zero(); + invalid.rows[4].is_code = Fr::ZERO; test_bytecode_circuit_unrolled::(k, vec![invalid], false); } // Mark the 7th byte as code (is data for the PUSH7) { let mut invalid = unrolled; - invalid.rows[7].is_code = Fr::one(); + invalid.rows[7].is_code = Fr::ONE; test_bytecode_circuit_unrolled::(k, vec![invalid], false); } } @@ -309,9 +309,9 @@ fn bytecode_soundness_bug_1() { if i >= unrolled_len { overwrite.rows.push(BytecodeRow { code_hash: code_hash.clone(), - tag: Fr::one(), + tag: Fr::ONE, index: Fr::from(index), - is_code: Fr::one(), + is_code: Fr::ONE, value: Fr::from((i % 10 + 1) as u64), }); index += 1; diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index 15b1a54f4b..292c8a2094 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -459,7 +459,7 @@ impl CopyCircuitConfig { || "q_enable", self.q_enable, *offset, - || Value::known(F::one()), + || Value::known(F::ONE), )?; // is_last, value, is_pad, is_code @@ -561,7 +561,7 @@ impl CopyCircuitConfig { || "q_enable", self.q_enable, *offset, - || Value::known(F::one()), + || Value::known(F::ONE), )?; // q_step if *offset % 2 == 0 { @@ -574,89 +574,89 @@ impl CopyCircuitConfig { || format!("assign is_first {}", *offset), self.copy_table.is_first, *offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // is_last region.assign_advice( || format!("assign is_last {}", *offset), self.is_last, *offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // id region.assign_advice( || format!("assign id {}", *offset), self.copy_table.id, *offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // addr region.assign_advice( || format!("assign addr {}", *offset), self.copy_table.addr, *offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // src_addr_end region.assign_advice( || format!("assign src_addr_end {}", *offset), self.copy_table.src_addr_end, *offset, - || Value::known(F::one()), + || Value::known(F::ONE), )?; // bytes_left region.assign_advice( || format!("assign bytes_left {}", *offset), self.copy_table.bytes_left, *offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // value region.assign_advice( || format!("assign value {}", *offset), self.value, *offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // rlc_acc region.assign_advice( || format!("assign rlc_acc {}", *offset), self.copy_table.rlc_acc, *offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // is_code region.assign_advice( || format!("assign is_code {}", *offset), self.is_code, *offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // is_pad region.assign_advice( || format!("assign is_pad {}", *offset), self.is_pad, *offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // rw_counter region.assign_advice( || format!("assign rw_counter {}", *offset), self.copy_table.rw_counter, *offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // rwc_inc_left region.assign_advice( || format!("assign rwc_inc_left {}", *offset), self.copy_table.rwc_inc_left, *offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; // tag tag_chip.assign(region, *offset, &CopyDataType::Padding)?; // Assign LT gadget - lt_chip.assign(region, *offset, F::zero(), F::one())?; + lt_chip.assign(region, *offset, F::ZERO, F::ONE)?; *offset += 1; diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 3144697a47..e1f19121ed 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -140,7 +140,7 @@ impl EvmCircuitConfig { layouter.assign_region( || "fixed table", |mut region| { - for (offset, row) in std::iter::once([F::zero(); 4]) + for (offset, row) in std::iter::once([F::ZERO; 4]) .chain(fixed_table_tags.iter().flat_map(|tag| tag.build())) .enumerate() { diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index c7bea3d2cd..e96db57c28 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -25,7 +25,6 @@ use crate::{ use eth_types::{evm_unimplemented, Field}; use gadgets::util::not; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Layouter, Region, Value}, plonk::{ Advice, Column, ConstraintSystem, Error, Expression, FirstPhase, Fixed, SecondPhase, @@ -179,7 +178,7 @@ use sstore::SstoreGadget; use stop::StopGadget; use swap::SwapGadget; -pub(crate) trait ExecutionGadget { +pub(crate) trait ExecutionGadget { const NAME: &'static str; const EXECUTION_STATE: ExecutionState; @@ -856,10 +855,10 @@ impl ExecutionConfig { || "step selector", self.q_step, offset, - || Value::known(if idx == 0 { F::one() } else { F::zero() }), + || Value::known(if idx == 0 { F::ONE } else { F::ZERO }), )?; let value = if idx == 0 { - F::zero() + F::ZERO } else { F::from((height - idx) as u64) }; @@ -873,7 +872,7 @@ impl ExecutionConfig { || "step height inv", self.num_rows_inv, offset, - || Value::known(value.invert().unwrap_or(F::zero())), + || Value::known(value.invert().unwrap_or(F::ZERO)), )?; } Ok(()) @@ -1011,13 +1010,13 @@ impl ExecutionConfig { || "step height", self.num_rows_until_next_step, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; region.assign_advice( || "step height inv", self.q_step, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; Ok(()) @@ -1356,9 +1355,9 @@ impl ExecutionConfig { block: &Block, challenges: &Challenges>, ) { - let mut evm_randomness = F::zero(); + let mut evm_randomness = F::ZERO; challenges.evm_word().map(|v| evm_randomness = v); - let mut lookup_randomness = F::zero(); + let mut lookup_randomness = F::ZERO; challenges.lookup_input().map(|v| lookup_randomness = v); if evm_randomness.is_zero_vartime() || lookup_randomness.is_zero_vartime() { // challenges not ready diff --git a/zkevm-circuits/src/evm_circuit/execution/balance.rs b/zkevm-circuits/src/evm_circuit/execution/balance.rs index 9a923308ff..fb7606a39a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/balance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/balance.rs @@ -125,7 +125,7 @@ impl ExecutionGadget for BalanceGadget { let (_, is_warm) = block.rws[step.rw_indices[4]].tx_access_list_value_pair(); self.is_warm - .assign(region, offset, Value::known(F::from(is_warm)))?; + .assign(region, offset, Value::known(F::from(is_warm as u64)))?; let code_hash = block.rws[step.rw_indices[5]].account_value_pair().0; self.code_hash diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index 1958b308b7..a7099163d8 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -490,7 +490,7 @@ impl ExecutionGadget for BeginTxGadget { self.is_caller_callee_equal.assign( region, offset, - Value::known(F::from(caller_address == callee_address)), + Value::known(F::from((caller_address == callee_address) as u64)), )?; self.tx_is_create .assign(region, offset, Value::known(F::from(tx.is_create as u64)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/comparator.rs b/zkevm-circuits/src/evm_circuit/execution/comparator.rs index c11803c352..e22fbf4864 100644 --- a/zkevm-circuits/src/evm_circuit/execution/comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/comparator.rs @@ -133,7 +133,7 @@ impl ExecutionGadget for ComparatorGadget { F::from(OpcodeId::GT.as_u8() as u64), )?; - let indices = if is_gt == F::one() { + let indices = if is_gt == F::ONE { [step.rw_indices[1], step.rw_indices[0]] } else { [step.rw_indices[0], step.rw_indices[1]] diff --git a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs index fcfad5f2cc..9261a6801d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -296,7 +296,7 @@ impl ExecutionGadget for EndTxGadget { Value::known(F::from(current_cumulative_gas_used)), )?; self.is_first_tx - .assign(region, offset, F::from(tx.id as u64), F::one())?; + .assign(region, offset, F::from(tx.id as u64), F::ONE)?; self.is_persistent.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs index e759be1692..65f901ede5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs @@ -122,8 +122,10 @@ impl ExecutionGadget for ErrorOOGStaticMemoryGadget { region, offset, step.memory_word_size(), - [address_low::value(address.to_le_bytes()) - + if is_mstore8 == F::one() { 1 } else { 32 }], + [ + address_low::value(address.to_le_bytes()) + + if is_mstore8 == F::ONE { 1 } else { 32 }, + ], )?; // Gas insufficient check diff --git a/zkevm-circuits/src/evm_circuit/execution/exp.rs b/zkevm-circuits/src/evm_circuit/execution/exp.rs index 51347f3e36..6e4fe08250 100644 --- a/zkevm-circuits/src/evm_circuit/execution/exp.rs +++ b/zkevm-circuits/src/evm_circuit/execution/exp.rs @@ -248,7 +248,7 @@ impl ExecutionGadget for ExponentiationGadget { self.exponent_hi_is_zero .assign(region, offset, exponent_hi_scalar)?; self.exponent_lo_is_one - .assign(region, offset, exponent_lo_scalar, F::one())?; + .assign(region, offset, exponent_lo_scalar, F::ONE)?; let (base_sq, _) = base.overflowing_mul(base); self.zero_rlc diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs index e85deb09db..bd635a7018 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs @@ -127,7 +127,7 @@ impl ExecutionGadget for ExtcodesizeGadget { let (_, is_warm) = block.rws[step.rw_indices[4]].tx_access_list_value_pair(); self.is_warm - .assign(region, offset, Value::known(F::from(is_warm)))?; + .assign(region, offset, Value::known(F::from(is_warm as u64)))?; let code_hash = block.rws[step.rw_indices[5]].account_value_pair().0; self.code_hash diff --git a/zkevm-circuits/src/evm_circuit/execution/logs.rs b/zkevm-circuits/src/evm_circuit/execution/logs.rs index a2be9af931..68fb0aed34 100644 --- a/zkevm-circuits/src/evm_circuit/execution/logs.rs +++ b/zkevm-circuits/src/evm_circuit/execution/logs.rs @@ -221,10 +221,10 @@ impl ExecutionGadget for LogGadget { let mut topic = region.word_rlc(U256::zero()); if i < topic_count { topic = region.word_rlc(block.rws[topic_stack_entry].stack_value()); - self.topic_selectors[i].assign(region, offset, Value::known(F::one()))?; + self.topic_selectors[i].assign(region, offset, Value::known(F::ONE))?; topic_stack_entry.1 += 1; } else { - self.topic_selectors[i].assign(region, offset, Value::known(F::zero()))?; + self.topic_selectors[i].assign(region, offset, Value::known(F::ZERO))?; } self.phase2_topics[i].assign(region, offset, topic)?; } diff --git a/zkevm-circuits/src/evm_circuit/execution/memory.rs b/zkevm-circuits/src/evm_circuit/execution/memory.rs index 0adc47f0ad..0ec073b23a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/memory.rs @@ -165,7 +165,7 @@ impl ExecutionGadget for MemoryGadget { region, offset, step.memory_word_size(), - [address.as_u64() + if is_mstore8 == F::one() { 1 } else { 32 }], + [address.as_u64() + if is_mstore8 == F::ONE { 1 } else { 32 }], )?; Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs index 20308cb23c..b2fad3fbdf 100644 --- a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs +++ b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs @@ -253,8 +253,11 @@ impl ExecutionGadget for ReturnRevertGadget { self.memory_expansion .assign(region, offset, step.memory_word_size(), [range])?; - self.is_success - .assign(region, offset, Value::known(call.is_success.into()))?; + self.is_success.assign( + region, + offset, + Value::known(F::from(call.is_success as u64)), + )?; if !call.is_root && !call.is_create() { for (cell, value) in [ diff --git a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs index 11284033a1..d243fef860 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs @@ -206,7 +206,7 @@ impl ExecutionGadget for SignedComparatorGadget { self.a_lt_b.assign( region, offset, - Value::known(if a < b { F::one() } else { F::zero() }), + Value::known(if a < b { F::ONE } else { F::ZERO }), )?; self.a.assign(region, offset, Some(a_le_bytes))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/signextend.rs b/zkevm-circuits/src/evm_circuit/execution/signextend.rs index edd543d0ee..02427df086 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signextend.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signextend.rs @@ -195,7 +195,7 @@ impl ExecutionGadget for SignextendGadget { // Set the sign byte let mut sign = 0u64; - if index[0] < 31 && msb_sum_zero == F::one() { + if index[0] < 31 && msb_sum_zero == F::ONE { sign = (value[index[0] as usize] >> 7) as u64; } self.sign_byte diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index b0f8fb6b60..326a4a9a08 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -8,9 +8,8 @@ use crate::{ util::Expr, }; use bus_mapping::evm::OpcodeId; -use eth_types::ToWord; +use eth_types::{Field, ToWord}; use halo2_proofs::{ - arithmetic::FieldExt, circuit::Value, plonk::{Advice, Column, ConstraintSystem, Error, Expression}, }; @@ -371,7 +370,7 @@ pub(crate) struct DynamicSelectorHalf { pub(crate) target_pairs: Vec>, } -impl DynamicSelectorHalf { +impl DynamicSelectorHalf { pub(crate) fn new(cell_manager: &mut CellManager, count: usize) -> Self { let target_pairs = cell_manager.query_cells(CellType::StoragePhase1, (count + 1) / 2); let target_odd = cell_manager.query_cell(CellType::StoragePhase1); @@ -440,17 +439,13 @@ impl DynamicSelectorHalf { self.target_odd.assign( region, offset, - Value::known(if odd { F::one() } else { F::zero() }), + Value::known(if odd { F::ONE } else { F::ZERO }), )?; for (index, cell) in self.target_pairs.iter().enumerate() { cell.assign( region, offset, - Value::known(if index == pair_index { - F::one() - } else { - F::zero() - }), + Value::known(if index == pair_index { F::ONE } else { F::ZERO }), )?; } Ok(()) @@ -497,7 +492,7 @@ pub(crate) struct Step { pub(crate) cell_manager: CellManager, } -impl Step { +impl Step { pub(crate) fn new( meta: &mut ConstraintSystem, advices: [Column; STEP_WIDTH], @@ -566,9 +561,11 @@ impl Step { self.state .is_root .assign(region, offset, Value::known(F::from(call.is_root as u64)))?; - self.state - .is_create - .assign(region, offset, Value::known(F::from(call.is_create())))?; + self.state.is_create.assign( + region, + offset, + Value::known(F::from(call.is_create() as u64)), + )?; self.state .code_hash .assign(region, offset, region.word_rlc(call.code_hash.to_word()))?; diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index c9eab33f0a..e7d5572d00 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -35,37 +35,37 @@ impl FixedTableTag { pub fn build(&self) -> Box> { let tag = F::from(*self as u64); match self { - Self::Zero => Box::new((0..1).map(move |_| [tag, F::zero(), F::zero(), F::zero()])), + Self::Zero => Box::new((0..1).map(move |_| [tag, F::ZERO, F::ZERO, F::ZERO])), Self::Range5 => { - Box::new((0..5).map(move |value| [tag, F::from(value), F::zero(), F::zero()])) + Box::new((0..5).map(move |value| [tag, F::from(value), F::ZERO, F::ZERO])) } Self::Range16 => { - Box::new((0..16).map(move |value| [tag, F::from(value), F::zero(), F::zero()])) + Box::new((0..16).map(move |value| [tag, F::from(value), F::ZERO, F::ZERO])) } Self::Range32 => { - Box::new((0..32).map(move |value| [tag, F::from(value), F::zero(), F::zero()])) + Box::new((0..32).map(move |value| [tag, F::from(value), F::ZERO, F::ZERO])) } Self::Range64 => { - Box::new((0..64).map(move |value| [tag, F::from(value), F::zero(), F::zero()])) + Box::new((0..64).map(move |value| [tag, F::from(value), F::ZERO, F::ZERO])) } Self::Range128 => { - Box::new((0..128).map(move |value| [tag, F::from(value), F::zero(), F::zero()])) + Box::new((0..128).map(move |value| [tag, F::from(value), F::ZERO, F::ZERO])) } Self::Range256 => { - Box::new((0..256).map(move |value| [tag, F::from(value), F::zero(), F::zero()])) + Box::new((0..256).map(move |value| [tag, F::from(value), F::ZERO, F::ZERO])) } Self::Range512 => { - Box::new((0..512).map(move |value| [tag, F::from(value), F::zero(), F::zero()])) + Box::new((0..512).map(move |value| [tag, F::from(value), F::ZERO, F::ZERO])) } Self::Range1024 => { - Box::new((0..1024).map(move |value| [tag, F::from(value), F::zero(), F::zero()])) + Box::new((0..1024).map(move |value| [tag, F::from(value), F::ZERO, F::ZERO])) } Self::SignByte => Box::new((0..256).map(move |value| { [ tag, F::from(value), F::from((value >> 7) * 0xFFu64), - F::zero(), + F::ZERO, ] })), Self::BitwiseAnd => Box::new((0..256).flat_map(move |lhs| { @@ -82,7 +82,7 @@ impl FixedTableTag { execution_state.responsible_opcodes().into_iter().map( move |responsible_opcode| { let (op, aux) = match responsible_opcode { - ResponsibleOp::Op(op) => (op, F::zero()), + ResponsibleOp::Op(op) => (op, F::ZERO), ResponsibleOp::InvalidStackPtr(op, stack_ptr) => { (op, F::from(u64::from(stack_ptr))) } @@ -113,7 +113,7 @@ impl FixedTableTag { tag, F::from(opcode.as_u64()), F::from(opcode.constant_gas_cost().0), - F::zero(), + F::ZERO, ] }), ), diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index eba13c13f1..5453227232 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -10,9 +10,8 @@ use crate::{ witness::{Block, ExecStep, Rw, RwMap}, }; use bus_mapping::state_db::CodeDB; -use eth_types::{Address, ToLittleEndian, ToWord, U256}; +use eth_types::{Address, Field, ToLittleEndian, ToWord, U256}; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{AssignedCell, Region, Value}, plonk::{Advice, Assigned, Column, ConstraintSystem, Error, Expression, VirtualCells}, poly::Rotation, @@ -41,7 +40,7 @@ pub(crate) struct Cell { cell_column_index: usize, } -impl Cell { +impl Cell { pub(crate) fn new( meta: &mut VirtualCells, column: Column, @@ -76,18 +75,18 @@ impl Cell { } } -impl Expr for Cell { +impl Expr for Cell { fn expr(&self) -> Expression { self.expression.clone() } } -impl Expr for &Cell { +impl Expr for &Cell { fn expr(&self) -> Expression { self.expression.clone() } } -pub struct CachedRegion<'r, 'b, F: FieldExt> { +pub struct CachedRegion<'r, 'b, F: Field> { region: &'r mut Region<'b, F>, advice: Vec>, challenges: &'r Challenges>, @@ -96,7 +95,7 @@ pub struct CachedRegion<'r, 'b, F: FieldExt> { height_start: usize, } -impl<'r, 'b, F: FieldExt> CachedRegion<'r, 'b, F> { +impl<'r, 'b, F: Field> CachedRegion<'r, 'b, F> { /// New cached region pub(crate) fn new( region: &'r mut Region<'b, F>, @@ -107,7 +106,7 @@ impl<'r, 'b, F: FieldExt> CachedRegion<'r, 'b, F> { ) -> Self { Self { region, - advice: vec![vec![F::zero(); height]; advice_columns.len()], + advice: vec![vec![F::ZERO; height]; advice_columns.len()], challenges, width_start: advice_columns[0].index(), height_start, @@ -231,7 +230,7 @@ impl Hash for StoredExpression { } } -impl StoredExpression { +impl StoredExpression { pub fn assign( &self, region: &mut CachedRegion<'_, '_, F>, @@ -277,7 +276,7 @@ pub(crate) enum CellType { impl CellType { // The phase that given `Expression` becomes evaluateable. - fn expr_phase(expr: &Expression) -> u8 { + fn expr_phase(expr: &Expression) -> u8 { use Expression::*; match expr { Challenge(challenge) => challenge.phase() + 1, @@ -298,7 +297,7 @@ impl CellType { } /// Return the storage cell of the expression - pub(crate) fn storage_for_expr(expr: &Expression) -> CellType { + pub(crate) fn storage_for_expr(expr: &Expression) -> CellType { Self::storage_for_phase(Self::expr_phase::(expr)) } } @@ -311,7 +310,7 @@ pub(crate) struct CellColumn { pub(crate) expr: Expression, } -impl Expr for CellColumn { +impl Expr for CellColumn { fn expr(&self) -> Expression { self.expr.clone() } @@ -325,7 +324,7 @@ pub(crate) struct CellManager { columns: Vec>, } -impl CellManager { +impl CellManager { pub(crate) fn new( meta: &mut ConstraintSystem, height: usize, @@ -465,7 +464,7 @@ pub(crate) struct RandomLinearCombination { pub(crate) cells: [Cell; N], } -impl RandomLinearCombination { +impl RandomLinearCombination { const N_BYTES: usize = N; pub(crate) fn new(cells: [Cell; N], randomness: Expression) -> Self { @@ -493,7 +492,7 @@ impl RandomLinearCombination { } } -impl Expr for RandomLinearCombination { +impl Expr for RandomLinearCombination { fn expr(&self) -> Expression { self.expression.clone() } @@ -505,15 +504,16 @@ pub(crate) type MemoryAddress = RandomLinearCombination>(bytes: &[E]) -> Expression { + pub(crate) fn expr>(bytes: &[E]) -> Expression { debug_assert!( bytes.len() <= MAX_N_BYTES_INTEGER, "Too many bytes to compose an integer in field" ); let mut value = 0.expr(); - let mut multiplier = F::one(); + let mut multiplier = F::ONE; for byte in bytes.iter() { value = value + byte.expr() * multiplier; multiplier *= F::from(256); @@ -521,13 +521,13 @@ pub(crate) mod from_bytes { value } - pub(crate) fn value(bytes: &[u8]) -> F { + pub(crate) fn value(bytes: &[u8]) -> F { debug_assert!( bytes.len() <= MAX_N_BYTES_INTEGER, "Too many bytes to compose an integer in field" ); - let mut value = F::zero(); - let mut multiplier = F::one(); + let mut value = F::ZERO; + let mut multiplier = F::ONE; for byte in bytes.iter() { value += F::from(*byte as u64) * multiplier; multiplier *= F::from(256); @@ -542,9 +542,10 @@ pub(crate) mod rlc { use std::ops::{Add, Mul}; use crate::util::Expr; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use eth_types::Field; + use halo2_proofs::plonk::Expression; - pub(crate) fn expr>(expressions: &[E], randomness: E) -> Expression { + pub(crate) fn expr>(expressions: &[E], randomness: E) -> Expression { if !expressions.is_empty() { generic(expressions.iter().map(|e| e.expr()), randomness.expr()) } else { @@ -552,7 +553,7 @@ pub(crate) mod rlc { } } - pub(crate) fn value<'a, F: FieldExt, I>(values: I, randomness: F) -> F + pub(crate) fn value<'a, F: Field, I>(values: I, randomness: F) -> F where I: IntoIterator, ::IntoIter: DoubleEndedIterator, @@ -564,7 +565,7 @@ pub(crate) mod rlc { if !values.is_empty() { generic(values, randomness) } else { - F::zero() + F::ZERO } } @@ -581,13 +582,13 @@ pub(crate) mod rlc { } } -/// Returns 2**by as FieldExt -pub(crate) fn pow_of_two(by: usize) -> F { - F::from(2).pow(&[by as u64, 0, 0, 0]) +/// Returns 2**by as Field +pub(crate) fn pow_of_two(by: usize) -> F { + F::from(2).pow([by as u64, 0, 0, 0]) } /// Returns 2**by as Expression -pub(crate) fn pow_of_two_expr(by: usize) -> Expression { +pub(crate) fn pow_of_two_expr(by: usize) -> Expression { Expression::Constant(pow_of_two(by)) } diff --git a/zkevm-circuits/src/evm_circuit/util/instrumentation.rs b/zkevm-circuits/src/evm_circuit/util/instrumentation.rs index ec744060cd..7f03fe6864 100644 --- a/zkevm-circuits/src/evm_circuit/util/instrumentation.rs +++ b/zkevm-circuits/src/evm_circuit/util/instrumentation.rs @@ -3,7 +3,7 @@ use crate::evm_circuit::{ table::Table, util::{constraint_builder::EVMConstraintBuilder, CellType}, }; -use halo2_proofs::arithmetic::FieldExt; +use eth_types::Field; use itertools::Itertools; type StepSize = Vec<(CellType, ColumnSize)>; @@ -20,7 +20,7 @@ pub(crate) struct Instrument { impl Instrument { /// Collects `CellManager` stats from a compiled EVMCircuit in order to /// extract metrics. - pub(crate) fn on_gadget_built( + pub(crate) fn on_gadget_built( &mut self, execution_state: ExecutionState, cb: &EVMConstraintBuilder, diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs index a0bb5a9c25..02c514843a 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs @@ -63,9 +63,9 @@ impl BatchedIsZeroGadget { if let Some(inverse) = values.iter().find_map(|value| Option::from(value.invert())) { self.nonempty_witness .assign(region, offset, Value::known(inverse))?; - F::zero() + F::ZERO } else { - F::one() + F::ONE }; self.is_zero.assign(region, offset, Value::known(is_zero))?; diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs index f02fefb15f..e57dbaade3 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs @@ -77,7 +77,7 @@ impl ByteSizeGadget { byte_index.assign( region, offset, - Value::known(if i == byte_size { F::one() } else { F::zero() }), + Value::known(if i == byte_size { F::ONE } else { F::ZERO }), )?; } if byte_size > 0 { @@ -95,7 +95,7 @@ impl ByteSizeGadget { self.most_significant_nonzero_byte_inverse.assign( region, offset, - Value::known(F::zero()), + Value::known(F::ZERO), )?; } Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs index 85a921bd8e..9f7d3f252f 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs @@ -46,12 +46,12 @@ impl IsZeroGadget { offset: usize, value: F, ) -> Result { - let inverse = value.invert().unwrap_or(F::zero()); + let inverse = value.invert().unwrap_or(F::ZERO); self.inverse.assign(region, offset, Value::known(inverse))?; Ok(if value.is_zero().into() { - F::one() + F::ONE } else { - F::zero() + F::ZERO }) } diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs index ef5ca9afce..51366b5480 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs @@ -64,11 +64,11 @@ impl LtGadget { self.lt.assign( region, offset, - Value::known(if lt { F::one() } else { F::zero() }), + Value::known(if lt { F::ONE } else { F::ZERO }), )?; // Set the bytes of diff - let diff = (lhs - rhs) + (if lt { self.range } else { F::zero() }); + let diff = (lhs - rhs) + (if lt { self.range } else { F::ZERO }); let diff_bytes = diff.to_repr(); for (idx, diff) in self.diff.iter().enumerate() { diff.assign( @@ -78,7 +78,7 @@ impl LtGadget { )?; } - Ok((if lt { F::one() } else { F::zero() }, diff_bytes.to_vec())) + Ok((if lt { F::ONE } else { F::ZERO }, diff_bytes.to_vec())) } pub(crate) fn diff_bytes(&self) -> Vec> { diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/pair_select.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/pair_select.rs index 898c4c4801..ab1c98084d 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/pair_select.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/pair_select.rs @@ -53,10 +53,10 @@ impl PairSelectGadget { a: F, _b: F, ) -> Result<(F, F), Error> { - let is_a = if value == a { F::one() } else { F::zero() }; + let is_a = if value == a { F::ONE } else { F::ZERO }; self.is_a.assign(region, offset, Value::known(is_a))?; - Ok((is_a, F::one() - is_a)) + Ok((is_a, F::ONE - is_a)) } } diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs index 81dfe9c205..1cae8e56cf 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs @@ -437,7 +437,7 @@ mod test { .assign(region, offset, Value::known(F::from(input_len)))?; if IS_CREATE2 { for c in self.create_input_rlc_expected.iter() { - c.assign(region, offset, Value::known(F::zero()))?; + c.assign(region, offset, Value::known(F::ZERO))?; } for (c, v) in self.create2_input_rlc_expected.iter().zip( [ @@ -459,7 +459,7 @@ mod test { c.assign(region, offset, Value::known(F::from(v as u64)))?; } for c in self.create2_input_rlc_expected.iter() { - c.assign(region, offset, Value::known(F::zero()))?; + c.assign(region, offset, Value::known(F::ZERO))?; } } diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs index 0b8e6339f5..823cf99bd4 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs @@ -41,7 +41,7 @@ pub(crate) const WORD_SIGNED_MAX: Word = U256([u64::MAX, u64::MAX, u64::MAX, i64 pub(crate) const WORD_SIGNED_MIN: Word = U256([0, 0, 0, i64::MIN as _]); pub(crate) fn generate_power_of_randomness(randomness: F) -> Vec { - (1..32).map(|exp| randomness.pow(&[exp, 0, 0, 0])).collect() + (1..32).map(|exp| randomness.pow([exp, 0, 0, 0])).collect() } pub(crate) trait MathGadgetContainer: Clone { @@ -214,7 +214,7 @@ impl> Circuit for UnitTestMathGadgetBaseC layouter.assign_region( || "fixed table", |mut region| { - for (offset, row) in std::iter::once([F::zero(); 4]) + for (offset, row) in std::iter::once([F::ZERO; 4]) .chain( FixedTableTag::iter() .filter(|t| { diff --git a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs index 87b6f52683..b07972112e 100644 --- a/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/memory_gadget.rs @@ -509,7 +509,7 @@ impl // assign bound_dist and bound_dist_is_zero let oob = addr_start + idx as u64 >= addr_end; let bound_dist = if oob { - F::zero() + F::ZERO } else { F::from(addr_end - addr_start - idx as u64) }; diff --git a/zkevm-circuits/src/exp_circuit.rs b/zkevm-circuits/src/exp_circuit.rs index 5b895ac1db..4da5979a0f 100644 --- a/zkevm-circuits/src/exp_circuit.rs +++ b/zkevm-circuits/src/exp_circuit.rs @@ -382,14 +382,14 @@ impl ExpCircuitConfig { || format!("exp_circuit: {:?}: {}", self.exp_table.is_step, offset), self.exp_table.is_step, *offset, - || Value::known(F::one()), + || Value::known(F::ONE), )?; for i in 1..OFFSET_INCREMENT { region.assign_fixed( || format!("exp_circuit: {:?}: {}", self.exp_table.is_step, *offset + i), self.exp_table.is_step, *offset + i, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; } // mul_chip has 7 rows, exp_table has 4 rows. So we increment the offset by @@ -449,14 +449,14 @@ impl ExpCircuitConfig { || format!("unused rows: {}", offset + i), *column, offset + i, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; } region.assign_fixed( || format!("unused rows: {}", offset + i), self.exp_table.is_step, offset + i, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; } diff --git a/zkevm-circuits/src/keccak_circuit.rs b/zkevm-circuits/src/keccak_circuit.rs index c2088a174c..983cb45894 100644 --- a/zkevm-circuits/src/keccak_circuit.rs +++ b/zkevm-circuits/src/keccak_circuit.rs @@ -890,16 +890,20 @@ impl KeccakCircuitConfig { ) -> Result<(), Error> { // Fixed selectors for (name, column, value) in &[ - ("q_enable", self.q_enable, F::from(row.q_enable)), - ("q_first", self.q_first, F::from(offset == 0)), - ("q_round", self.q_round, F::from(row.q_round)), - ("q_round_last", self.q_round_last, F::from(row.q_round_last)), - ("q_absorb", self.q_absorb, F::from(row.q_absorb)), - ("q_padding", self.q_padding, F::from(row.q_padding)), + ("q_enable", self.q_enable, F::from(row.q_enable as u64)), + ("q_first", self.q_first, F::from((offset == 0) as u64)), + ("q_round", self.q_round, F::from(row.q_round as u64)), + ( + "q_round_last", + self.q_round_last, + F::from(row.q_round_last as u64), + ), + ("q_absorb", self.q_absorb, F::from(row.q_absorb as u64)), + ("q_padding", self.q_padding, F::from(row.q_padding as u64)), ( "q_padding_last", self.q_padding_last, - F::from(row.q_padding_last), + F::from(row.q_padding_last as u64), ), ] { region.assign_fixed( @@ -914,7 +918,7 @@ impl KeccakCircuitConfig { region, offset, [ - Value::known(F::from(row.is_final)), + Value::known(F::from(row.is_final as u64)), row.data_rlc, Value::known(F::from(row.length as u64)), row.hash_rlc, diff --git a/zkevm-circuits/src/keccak_circuit/cell_manager.rs b/zkevm-circuits/src/keccak_circuit/cell_manager.rs index c0c671bddb..0706ac93a7 100644 --- a/zkevm-circuits/src/keccak_circuit/cell_manager.rs +++ b/zkevm-circuits/src/keccak_circuit/cell_manager.rs @@ -1,7 +1,7 @@ use crate::keccak_circuit::util::extract_field; +use eth_types::Field; use gadgets::util::Expr; use halo2_proofs::{ - arithmetic::FieldExt, circuit::Value, plonk::{Advice, Column, ConstraintSystem, Expression, VirtualCells}, poly::Rotation, @@ -18,7 +18,7 @@ pub(crate) struct Cell { pub(crate) rotation: i32, } -impl Cell { +impl Cell { pub(crate) fn new( meta: &mut VirtualCells, column: Column, @@ -75,13 +75,13 @@ impl Cell { } } -impl Expr for Cell { +impl Expr for Cell { fn expr(&self) -> Expression { self.expression.clone() } } -impl Expr for &Cell { +impl Expr for &Cell { fn expr(&self) -> Expression { self.expression.clone() } @@ -103,7 +103,7 @@ pub(crate) struct CellManager { num_unused_cells: usize, } -impl CellManager { +impl CellManager { pub(crate) fn new(height: usize) -> Self { Self { height, diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index 903de1f3a4..3c1e93999d 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -2,7 +2,6 @@ use super::{cell_manager::*, param::*, util::*}; use crate::{evm_circuit::util::rlc, util::Challenges}; use eth_types::Field; use halo2_proofs::{ - arithmetic::FieldExt, circuit::Value, plonk::{Error, Expression}, }; @@ -92,7 +91,7 @@ pub(crate) struct KeccakRegion { pub(crate) rows: Vec>, } -impl KeccakRegion { +impl KeccakRegion { pub(crate) fn new() -> Self { Self { rows: Vec::new() } } @@ -103,7 +102,7 @@ impl KeccakRegion { } let row = &mut self.rows[offset]; while column >= row.len() { - row.push(F::zero()); + row.push(F::ZERO); } row[column] = value; } @@ -123,7 +122,7 @@ pub(crate) mod decode { } pub(crate) fn value(parts: Vec>) -> F { - parts.iter().rev().fold(F::zero(), |acc, part| { + parts.iter().rev().fold(F::ZERO, |acc, part| { acc * F::from(1u64 << (BIT_COUNT * part.num_bits)) + part.value }) } @@ -492,7 +491,7 @@ pub(crate) fn keccak( challenges: Challenges>, ) { let mut bits = into_bits(bytes); - let mut s = [[F::zero(); 5]; 5]; + let mut s = [[F::ZERO; 5]; 5]; let absorb_positions = get_absorb_positions(); let num_bytes_in_last_block = bytes.len() % RATE; let two = F::from(2u64); @@ -505,7 +504,7 @@ pub(crate) fn keccak( bits.push(1); let mut length = 0usize; - let mut data_rlc = Value::known(F::zero()); + let mut data_rlc = Value::known(F::ZERO); let chunks = bits.chunks(RATE_IN_BITS); let num_chunks = chunks.len(); for (idx, chunk) in chunks.enumerate() { @@ -529,7 +528,7 @@ pub(crate) fn keccak( let mut cell_managers = Vec::new(); let mut regions = Vec::new(); - let mut hash_rlc = Value::known(F::zero()); + let mut hash_rlc = Value::known(F::ZERO); let mut round_lengths = Vec::new(); let mut round_data_rlcs = Vec::new(); for round in 0..NUM_ROUNDS + 1 { @@ -582,7 +581,7 @@ pub(crate) fn keccak( transform::value(&mut cell_manager, &mut region, packed, false, |v| *v, true); cell_manager.start_region(); let mut is_paddings = Vec::new(); - let mut data_rlcs = vec![Value::known(F::zero()); get_num_rows_per_round()]; + let mut data_rlcs = vec![Value::known(F::ZERO); get_num_rows_per_round()]; for _ in input_bytes.iter() { is_paddings.push(cell_manager.query_cell_value()); } @@ -597,7 +596,7 @@ pub(crate) fn keccak( false }; paddings.push(padding); - is_padding.assign(&mut region, 0, if padding { F::one() } else { F::zero() }); + is_padding.assign(&mut region, 0, if padding { F::ONE } else { F::ZERO }); } data_rlcs[NUM_BYTES_PER_WORD] = data_rlc; // Start at 0 or forward the previous value. @@ -639,7 +638,7 @@ pub(crate) fn keccak( bc.push(bc_norm); } cell_manager.start_region(); - let mut os = [[F::zero(); 5]; 5]; + let mut os = [[F::ZERO; 5]; 5]; for i in 0..5 { let t = decode::value(bc[(i + 4) % 5].clone()) + decode::value(rotate(bc[(i + 1) % 5].clone(), 1, part_size)); @@ -701,7 +700,7 @@ pub(crate) fn keccak( // Chi let part_size_base = get_num_bits_per_base_chi_lookup(); let three_packed = pack::(&vec![3u8; part_size_base]); - let mut os = [[F::zero(); 5]; 5]; + let mut os = [[F::ZERO; 5]; 5]; for j in 0..5 { for i in 0..5 { let mut s_parts = Vec::new(); @@ -759,7 +758,7 @@ pub(crate) fn keccak( .evm_word() .map(|challenge_value| rlc::value(&hash_bytes_le, challenge_value)) } else { - Value::known(F::zero()) + Value::known(F::ZERO) }; // The words to squeeze out @@ -842,11 +841,11 @@ pub(crate) fn multi_keccak( q_round_last: false, q_padding: false, q_padding_last: false, - round_cst: F::zero(), + round_cst: F::ZERO, is_final: false, length: 0usize, - data_rlc: Value::known(F::zero()), - hash_rlc: Value::known(F::zero()), + data_rlc: Value::known(F::ZERO), + hash_rlc: Value::known(F::ZERO), cell_values: Vec::new(), }); } diff --git a/zkevm-circuits/src/keccak_circuit/util.rs b/zkevm-circuits/src/keccak_circuit/util.rs index 178ebe067a..48b819046e 100644 --- a/zkevm-circuits/src/keccak_circuit/util.rs +++ b/zkevm-circuits/src/keccak_circuit/util.rs @@ -2,7 +2,7 @@ use super::{keccak_packed_multi::keccak_unusable_rows, param::*}; use eth_types::{Field, ToScalar, Word}; -use halo2_proofs::{circuit::Value, halo2curves::FieldExt}; +use halo2_proofs::circuit::Value; use std::env::var; /// Description of which bits (positions) a part contains @@ -122,7 +122,7 @@ pub(crate) fn pack_with_base(bits: &[u8], base: usize) -> F { let base = F::from(base as u64); bits.iter() .rev() - .fold(F::zero(), |acc, &bit| acc * base + F::from(bit as u64)) + .fold(F::ZERO, |acc, &bit| acc * base + F::from(bit as u64)) } /// Decodes the bits using the position data found in the part info @@ -233,8 +233,8 @@ pub(crate) fn get_num_bits_per_lookup_impl(range: usize, log_height: usize) -> u num_bits as usize } -pub(crate) fn extract_field(value: Value) -> F { - let mut field = F::zero(); +pub(crate) fn extract_field(value: Value) -> F { + let mut field = F::ZERO; let _ = value.map(|f| { field = f; f @@ -280,7 +280,7 @@ pub(crate) mod to_bytes { let mut bytes = Vec::new(); for byte_bits in bits.chunks(8) { let mut value = 0.expr(); - let mut multiplier = F::one(); + let mut multiplier = F::ONE; for byte in byte_bits.iter() { value = value + byte.expr() * multiplier; multiplier *= F::from(2); diff --git a/zkevm-circuits/src/pi_circuit.rs b/zkevm-circuits/src/pi_circuit.rs index 22951d60dc..a5ff18a185 100644 --- a/zkevm-circuits/src/pi_circuit.rs +++ b/zkevm-circuits/src/pi_circuit.rs @@ -575,13 +575,13 @@ impl PiCircuitConfig { || "tx_id", self.tx_table.tx_id, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; region.assign_advice( || "tx_id_inv", self.tx_id_inv, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; region.assign_fixed( || "tag", @@ -593,31 +593,31 @@ impl PiCircuitConfig { || "index", self.tx_table.index, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; region.assign_advice( || "tx_value", self.tx_table.value, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; region.assign_advice( || "tx_value_inv", self.tx_value_inv, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; region.assign_advice( || "is_final", self.is_final, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; region.assign_advice( || "gas_cost", self.calldata_gas_cost, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; Ok(()) } @@ -638,14 +638,14 @@ impl PiCircuitConfig { // tx_id_inv = (tag - CallDataLength)^(-1) let tx_id_inv = if tag != TxFieldTag::CallDataLength { let x = F::from(tag as u64) - F::from(TxFieldTag::CallDataLength as u64); - x.invert().unwrap_or(F::zero()) + x.invert().unwrap_or(F::ZERO) } else { - F::zero() + F::ZERO }; let tag = F::from(tag as u64); let index = F::from(index as u64); let tx_value = tx_value; - let tx_value_inv = tx_value.invert().unwrap_or(F::zero()); + let tx_value_inv = tx_value.invert().unwrap_or(F::ZERO); self.q_tx_table.enable(region, offset)?; @@ -733,14 +733,14 @@ impl PiCircuitConfig { raw_pi_vals: &mut [F], ) -> Result<(), Error> { let tx_id = F::from(tx_id as u64); - let tx_id_inv = tx_id.invert().unwrap_or(F::zero()); + let tx_id_inv = tx_id.invert().unwrap_or(F::ZERO); let tx_id_diff = F::from(tx_id_next as u64) - tx_id; - let tx_id_diff_inv = tx_id_diff.invert().unwrap_or(F::zero()); + let tx_id_diff_inv = tx_id_diff.invert().unwrap_or(F::ZERO); let tag = F::from(TxFieldTag::CallData as u64); let index = F::from(index as u64); let tx_value = tx_value; - let tx_value_inv = tx_value.invert().unwrap_or(F::zero()); - let is_final = if is_final { F::one() } else { F::zero() }; + let tx_value_inv = tx_value.invert().unwrap_or(F::ZERO); + let is_final = if is_final { F::ONE } else { F::ZERO }; // Assign vals to raw_public_inputs column let tx_table_len = TX_LEN * self.max_txs + 1; @@ -839,15 +839,15 @@ impl PiCircuitConfig { || "zero", self.block_table.value, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; region.assign_advice( || "zero", self.raw_public_inputs, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; - raw_pi_vals[offset] = F::zero(); + raw_pi_vals[offset] = F::ZERO; offset += 1; // coinbase @@ -1208,7 +1208,7 @@ impl SubCircuit for PiCircuit { let rlc_rpi = rlc_rpi_col .iter() .rev() - .fold(F::zero(), |acc, val| acc * self.rand_rpi + val); + .fold(F::ZERO, |acc, val| acc * self.rand_rpi + val); // let block_hash = public_data // .eth_block @@ -1277,7 +1277,7 @@ impl SubCircuit for PiCircuit { region.name_column(|| "Public_Inputs", config.pi); let circuit_len = config.circuit_len(); - let mut raw_pi_vals = vec![F::zero(); circuit_len]; + let mut raw_pi_vals = vec![F::ZERO; circuit_len]; // Assign block table let block_values = self.public_data.get_block_table_values(); @@ -1310,7 +1310,7 @@ impl SubCircuit for PiCircuit { 0, TxFieldTag::Null, 0, - F::zero(), + F::ZERO, &mut raw_pi_vals, )?; offset += 1; @@ -1336,7 +1336,7 @@ impl SubCircuit for PiCircuit { TxFieldTag::CalleeAddress, tx.to_addr.to_scalar().expect("tx.to too big"), ), - (TxFieldTag::IsCreate, F::from(tx.is_create)), + (TxFieldTag::IsCreate, F::from(tx.is_create as u64)), ( TxFieldTag::Value, rlc(tx.value.to_le_bytes(), self.randomness), @@ -1368,7 +1368,7 @@ impl SubCircuit for PiCircuit { let txs = self.public_data.txs(); for (i, tx) in self.public_data.txs().iter().enumerate() { let call_data_length = tx.call_data.0.len(); - let mut gas_cost = F::zero(); + let mut gas_cost = F::ZERO; for (index, byte) in tx.call_data.0.iter().enumerate() { assert!(calldata_count < config.max_calldata); let is_final = index == call_data_length - 1; @@ -1413,9 +1413,9 @@ impl SubCircuit for PiCircuit { 0, // tx_id 0, 0, - F::zero(), + F::ZERO, false, - F::zero(), + F::ZERO, &mut raw_pi_vals, )?; offset += 1; @@ -1461,11 +1461,11 @@ fn raw_public_inputs_col( let mut offset = 0; let mut result = - vec![F::zero(); BLOCK_LEN + 1 + EXTRA_LEN + 3 * (TX_LEN * max_txs + 1) + max_calldata]; + vec![F::ZERO; BLOCK_LEN + 1 + EXTRA_LEN + 3 * (TX_LEN * max_txs + 1) + max_calldata]; // Insert Block Values // zero row - result[offset] = F::zero(); + result[offset] = F::ZERO; offset += 1; // coinbase result[offset] = block.coinbase.to_scalar().unwrap(); @@ -1512,9 +1512,9 @@ fn raw_public_inputs_col( let value_offset = index_offset + tx_table_len; // Insert zero row - result[id_offset + offset] = F::zero(); - result[index_offset + offset] = F::zero(); - result[value_offset + offset] = F::zero(); + result[id_offset + offset] = F::ZERO; + result[index_offset + offset] = F::ZERO; + result[value_offset + offset] = F::ZERO; offset += 1; @@ -1527,14 +1527,14 @@ fn raw_public_inputs_col( rlc(tx.gas_price.to_le_bytes(), randomness), tx.from_addr.to_scalar().expect("tx.from too big"), tx.to_addr.to_scalar().expect("tx.to too big"), - F::from(tx.is_create), + F::from(tx.is_create as u64), rlc(tx.value.to_le_bytes(), randomness), F::from(tx.call_data_len), F::from(tx.call_data_gas_cost), rlc(tx.tx_sign_hash, randomness), ] { result[id_offset + offset] = F::from((i + 1) as u64); - result[index_offset + offset] = F::zero(); + result[index_offset + offset] = F::ZERO; result[value_offset + offset] = *val; offset += 1; @@ -1551,7 +1551,7 @@ fn raw_public_inputs_col( } } for _ in calldata_count..max_calldata { - result[value_offset + offset] = F::zero(); + result[value_offset + offset] = F::ZERO; offset += 1; } diff --git a/zkevm-circuits/src/root_circuit.rs b/zkevm-circuits/src/root_circuit.rs index 440424fa18..4a45a62e1a 100644 --- a/zkevm-circuits/src/root_circuit.rs +++ b/zkevm-circuits/src/root_circuit.rs @@ -1,6 +1,7 @@ //! The Root circuit implementation. +use eth_types::Field; use halo2_proofs::{ - arithmetic::Field, + arithmetic::Field as Halo2Field, circuit::{Layouter, SimpleFloorPlanner, Value}, halo2curves::serde::SerdeObject, plonk::{Circuit, ConstraintSystem, Error}, @@ -39,6 +40,7 @@ impl<'a, M: MultiMillerLoop> RootCircuit<'a, M> where M::G1Affine: SerdeObject, M::G2Affine: SerdeObject, + M::Scalar: Field, { /// Create a `RootCircuit` with accumulator computed given a `SuperCircuit` /// proof and its instance. Returns `None` if given proof is invalid. @@ -50,7 +52,7 @@ where ) -> Result { let num_instances = super_circuit_protocol.num_instance.iter().sum::() + 4 * LIMBS; let instance = { - let mut instance = Ok(vec![M::Scalar::zero(); num_instances]); + let mut instance = Ok(vec![M::Scalar::ZERO; num_instances]); super_circuit_instances .as_ref() .zip(super_circuit_proof.as_ref()) @@ -102,7 +104,10 @@ where } } -impl<'a, M: MultiMillerLoop> Circuit for RootCircuit<'a, M> { +impl<'a, M: MultiMillerLoop> Circuit for RootCircuit<'a, M> +where + M::Scalar: Field, +{ type Config = AggregationConfig; type FloorPlanner = SimpleFloorPlanner; @@ -110,7 +115,7 @@ impl<'a, M: MultiMillerLoop> Circuit for RootCircuit<'a, M> { Self { svk: self.svk, snark: self.snark.without_witnesses(), - instance: vec![M::Scalar::zero(); self.instance.len()], + instance: vec![M::Scalar::ZERO; self.instance.len()], } } diff --git a/zkevm-circuits/src/root_circuit/aggregation.rs b/zkevm-circuits/src/root_circuit/aggregation.rs index b3321808e6..db3a2127fe 100644 --- a/zkevm-circuits/src/root_circuit/aggregation.rs +++ b/zkevm-circuits/src/root_circuit/aggregation.rs @@ -1,8 +1,9 @@ +use eth_types::Field; use halo2_proofs::{ - arithmetic::Field, circuit::{AssignedCell, Layouter, SimpleFloorPlanner, Value}, halo2curves::{ - group::prime::PrimeCurveAffine, pairing::Engine, serde::SerdeObject, CurveAffine, + ff::Field as Halo2Field, group::prime::PrimeCurveAffine, pairing::Engine, + serde::SerdeObject, CurveAffine, }, plonk::{Circuit, ConstraintSystem, Error}, poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG}, @@ -23,7 +24,7 @@ use snark_verifier::{ AccumulationDecider, AccumulationScheme, AccumulationSchemeProver, }, system::halo2::transcript, - util::arithmetic::{fe_to_limbs, FieldExt, MultiMillerLoop}, + util::arithmetic::{fe_to_limbs, MultiMillerLoop}, verifier::{self, plonk::PlonkProtocol, SnarkVerifier}, }; use std::{io, iter, rc::Rc}; @@ -178,12 +179,12 @@ impl AggregationConfig { } /// Returns `MainGate`. - pub fn main_gate(&self) -> MainGate { + pub fn main_gate(&self) -> MainGate { MainGate::new(self.main_gate_config.clone()) } /// Returns `RangeChip`. - pub fn range_chip(&self) -> RangeChip { + pub fn range_chip(&self) -> RangeChip { RangeChip::new(self.range_config.clone()) } @@ -196,7 +197,7 @@ impl AggregationConfig { } /// Load fixed lookup table for `RangeChip` - pub fn load_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + pub fn load_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { self.range_chip().load_table(layouter) } @@ -215,7 +216,10 @@ impl AggregationConfig { Vec>, ), Error, - > { + > + where + M::Scalar: Field, + { type PoseidonTranscript<'a, C, S> = transcript::halo2::PoseidonTranscript>, S, T, RATE, R_F, R_P>; let snarks = snarks.into_iter().collect_vec(); @@ -311,6 +315,7 @@ pub fn aggregate<'a, M: MultiMillerLoop>( where M::G1Affine: SerdeObject, M::G2Affine: SerdeObject, + M::Scalar: Field, { let svk = KzgSvk::::new(params.get_g()[0]); let dk = KzgDk::new(svk, params.g2(), params.s_g2()); @@ -385,6 +390,7 @@ impl<'a, M: MultiMillerLoop> TestAggregationCircuit<'a, M> where M::G1Affine: SerdeObject, M::G2Affine: SerdeObject, + M::Scalar: Field, { /// Create an Aggregation circuit with aggregated accumulator computed. /// Returns `None` if any given snark is invalid. @@ -434,7 +440,10 @@ where } } -impl<'a, M: MultiMillerLoop> Circuit for TestAggregationCircuit<'a, M> { +impl<'a, M: MultiMillerLoop> Circuit for TestAggregationCircuit<'a, M> +where + M::Scalar: Field, +{ type Config = AggregationConfig; type FloorPlanner = SimpleFloorPlanner; @@ -446,7 +455,7 @@ impl<'a, M: MultiMillerLoop> Circuit for TestAggregationCircuit<'a, M .iter() .map(SnarkWitness::without_witnesses) .collect(), - instances: vec![M::Scalar::zero(); self.instances.len()], + instances: vec![M::Scalar::ZERO; self.instances.len()], } } @@ -484,8 +493,9 @@ impl<'a, M: MultiMillerLoop> Circuit for TestAggregationCircuit<'a, M #[cfg(test)] pub mod test { use crate::root_circuit::{PoseidonTranscript, Snark, TestAggregationCircuit}; + use eth_types::Field; use halo2_proofs::{ - arithmetic::FieldExt, + arithmetic::Field as Halo2Field, circuit::{floor_planner::V1, Layouter, Value}, dev::{FailureLocation, MockProver, VerifyFailure}, halo2curves::{ @@ -550,7 +560,7 @@ pub mod test { impl StandardPlonkConfig { /// Configure for `StandardPlonk` - pub fn configure(meta: &mut ConstraintSystem) -> Self { + pub fn configure(meta: &mut ConstraintSystem) -> Self { let [w_l, w_r, w_o] = [(); 3].map(|_| meta.advice_column()); let [q_l, q_r, q_o, q_m, q_c] = [(); 5].map(|_| meta.fixed_column()); let pi = meta.instance_column(); @@ -584,7 +594,7 @@ pub mod test { #[derive(Clone, Copy)] pub struct StandardPlonk(F); - impl StandardPlonk { + impl StandardPlonk { /// Create a `StandardPlonk` with random instnace. pub fn rand(mut rng: R) -> Self { Self(F::from(rng.next_u32() as u64)) @@ -596,7 +606,7 @@ pub mod test { } } - impl Circuit for StandardPlonk { + impl Circuit for StandardPlonk { type Config = StandardPlonkConfig; type FloorPlanner = V1; @@ -622,7 +632,7 @@ pub mod test { // Assign some non-zero values to make sure the advice/fixed columns have // non-identity commitments. let a = region.assign_advice(|| "", w_l, 0, || Value::known(self.0))?; - region.assign_fixed(|| "", q_l, 0, || Value::known(-F::one()))?; + region.assign_fixed(|| "", q_l, 0, || Value::known(-F::ONE))?; a.copy_advice(|| "", &mut region, w_r, 1)?; a.copy_advice(|| "", &mut region, w_o, 2)?; region.assign_advice(|| "", w_l, 3, || Value::known(-F::from(5)))?; @@ -642,7 +652,7 @@ pub mod test { ) -> Vec> { // Preprocess let (pk, protocol) = { - let standard_plonk = StandardPlonk(Fr::zero()); + let standard_plonk = StandardPlonk(Fr::ZERO); let vk = keygen_vk(params, &standard_plonk).unwrap(); let pk = keygen_pk(params, vk, &standard_plonk).unwrap(); let protocol = compile( @@ -711,7 +721,7 @@ pub mod test { .unwrap(); let mut instances = aggregation.instances(); // Change the propagated inner snark's instance - instances[0][0] += Fr::one(); + instances[0][0] += Fr::ONE; // Then expect the verification to fail assert_eq!( MockProver::run(21, &aggregation, instances) diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index 3ad529e4f6..0270ca098d 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -227,7 +227,7 @@ impl StateCircuitConfig { || "selector", self.selector, offset, - || Value::known(F::one()), + || Value::known(F::ONE), )?; tag_chip.assign(region, offset, &row.tag())?; @@ -262,7 +262,7 @@ impl StateCircuitConfig { || "not_first_access", self.not_first_access, offset, - || Value::known(if is_first_access { F::zero() } else { F::one() }), + || Value::known(if is_first_access { F::ZERO } else { F::ONE }), )?; if is_first_access { @@ -276,12 +276,7 @@ impl StateCircuitConfig { state_root = new_root; } if matches!(row.tag(), RwTableTag::CallContext) && !row.is_write() { - assert_eq!( - row.value_assignment(randomness), - F::zero(), - "{:?}", - row - ); + assert_eq!(row.value_assignment(randomness), F::ZERO, "{:?}", row); } state_root }); diff --git a/zkevm-circuits/src/state_circuit/constraint_builder.rs b/zkevm-circuits/src/state_circuit/constraint_builder.rs index 6fbb1dc973..58706b5d82 100644 --- a/zkevm-circuits/src/state_circuit/constraint_builder.rs +++ b/zkevm-circuits/src/state_circuit/constraint_builder.rs @@ -670,7 +670,7 @@ fn from_digits(digits: &[Expression], base: Expression) -> Expre digits .iter() .rev() - .fold(Expression::Constant(F::zero()), |result, digit| { + .fold(Expression::Constant(F::ZERO), |result, digit| { digit.clone() + result * base.clone() }) } diff --git a/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs b/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs index e43c9b07d0..bea63c2d5c 100644 --- a/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs +++ b/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs @@ -196,7 +196,7 @@ impl Config { || "upper_limb_difference", self.selector, offset, - || Value::known(F::one()), + || Value::known(F::ONE), )?; let cur_be_limbs = rw_to_be_limbs(cur); diff --git a/zkevm-circuits/src/state_circuit/test.rs b/zkevm-circuits/src/state_circuit/test.rs index ac911d61b0..b8eb3841dc 100644 --- a/zkevm-circuits/src/state_circuit/test.rs +++ b/zkevm-circuits/src/state_circuit/test.rs @@ -382,7 +382,7 @@ fn address_limb_mismatch() { value: U256::zero(), value_prev: U256::zero(), }]; - let overrides = HashMap::from([((AdviceColumn::AddressLimb0, 0), Fr::zero())]); + let overrides = HashMap::from([((AdviceColumn::AddressLimb0, 0), Fr::ZERO)]); let result = verify_with_overrides(rows, overrides); @@ -401,7 +401,7 @@ fn address_limb_out_of_range() { }]; let overrides = HashMap::from([ ((AdviceColumn::AddressLimb0, 0), Fr::from(1 << 16)), - ((AdviceColumn::AddressLimb1, 0), Fr::zero()), + ((AdviceColumn::AddressLimb1, 0), Fr::ZERO), ]); let result = verify_with_overrides(rows, overrides); @@ -421,7 +421,7 @@ fn storage_key_mismatch() { tx_id: 4, committed_value: U256::from(34), }]; - let overrides = HashMap::from([((AdviceColumn::StorageKeyByte1, 0), Fr::one())]); + let overrides = HashMap::from([((AdviceColumn::StorageKeyByte1, 0), Fr::ONE)]); let result = verify_with_overrides(rows, overrides); @@ -442,7 +442,7 @@ fn storage_key_byte_out_of_range() { }]; let overrides = HashMap::from([ ((AdviceColumn::StorageKeyByte0, 0), Fr::from(0xcafeu64)), - ((AdviceColumn::StorageKeyByte1, 0), Fr::zero()), + ((AdviceColumn::StorageKeyByte1, 0), Fr::ZERO), ]); // This will trigger two errors: an RLC encoding error and the "fit into u8", we @@ -656,8 +656,8 @@ fn lexicographic_ordering_previous_limb_differences_nonzero() { // limb difference between the two rows here is still 1, so no additional // overrides are needed. let overrides = HashMap::from([ - ((AdviceColumn::LimbIndexBit1, 1), Fr::one()), - ((AdviceColumn::LimbIndexBit2, 1), Fr::one()), + ((AdviceColumn::LimbIndexBit1, 1), Fr::ONE), + ((AdviceColumn::LimbIndexBit2, 1), Fr::ONE), ]); let result = verify_with_overrides(rows, overrides); @@ -706,7 +706,7 @@ fn skipped_start_rw_counter() { // The original assignment is 1 << 16. Fr::from((1 << 16) + 1), ), - ((AdviceColumn::RwCounterLimb0, -1), Fr::one()), + ((AdviceColumn::RwCounterLimb0, -1), Fr::ONE), ]); let result = prover(vec![], overrides).verify_at_rows(N_ROWS - 1..N_ROWS, N_ROWS - 1..N_ROWS); @@ -740,7 +740,7 @@ fn bad_initial_memory_value() { let overrides = HashMap::from([ ((AdviceColumn::Value, 0), v), ((AdviceColumn::ValuePrev, 0), v), - ((AdviceColumn::IsZero, 0), Fr::zero()), + ((AdviceColumn::IsZero, 0), Fr::ZERO), ((AdviceColumn::NonEmptyWitness, 0), v.invert().unwrap()), ((AdviceColumn::InitialValue, 0), v), ]); @@ -829,9 +829,7 @@ fn invalid_tags() { if tags.contains(&i) { continue; } - let bits: [Fr; 4] = i - .as_bits() - .map(|bit| if bit { Fr::one() } else { Fr::zero() }); + let bits: [Fr; 4] = i.as_bits().map(|bit| if bit { Fr::ONE } else { Fr::ZERO }); let overrides = HashMap::from([ ((AdviceColumn::TagBit0, first_row_offset), bits[0]), ((AdviceColumn::TagBit1, first_row_offset), bits[1]), @@ -903,7 +901,7 @@ fn bad_initial_tx_refund_value() { ((AdviceColumn::IsWrite, 0), Fr::from(1)), ((AdviceColumn::Value, 0), v), ((AdviceColumn::ValuePrev, 0), v), - ((AdviceColumn::IsZero, 0), Fr::zero()), + ((AdviceColumn::IsZero, 0), Fr::ZERO), ((AdviceColumn::NonEmptyWitness, 0), v.invert().unwrap()), ((AdviceColumn::InitialValue, 0), v), ]); diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 41662a8261..f203e5d3cc 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -132,7 +132,7 @@ impl SubCircuitConfig for SuperCircuitConfig { // Use a mock randomness instead of the randomness derived from the challange // (either from mock or real prover) to help debugging assignments. let power_of_randomness: [Expression; 31] = array::from_fn(|i| { - Expression::Constant(F::from(mock_randomness).pow(&[1 + i as u64, 0, 0, 0])) + Expression::Constant(F::from(mock_randomness).pow([1 + i as u64, 0, 0, 0])) }); let challenges = Challenges::mock( diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index c1eddcbb83..338cae170d 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -18,7 +18,6 @@ use gadgets::{ util::{split_u256, split_u256_limb64}, }; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Layouter, Region, Value}, plonk::{Advice, Column, ConstraintSystem, Error, *}, poly::Rotation, @@ -206,7 +205,7 @@ impl TxTable { offset, &advice_columns, &self.tag, - &[(); 4].map(|_| Value::known(F::zero())), + &[(); 4].map(|_| Value::known(F::ZERO)), "all-zero", )?; offset += 1; @@ -235,10 +234,10 @@ impl TxTable { // Assign Tx calldata let padding_calldata = (sum_txs_calldata..max_calldata).map(|_| { [ - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(F::from(TxContextFieldTag::CallData as u64)), - Value::known(F::zero()), - Value::known(F::zero()), + Value::known(F::ZERO), + Value::known(F::ZERO), ] }); for row in calldata_assignments.into_iter().chain(padding_calldata) { @@ -487,7 +486,7 @@ impl LookupTable for RwTable { } impl RwTable { /// Construct a new RwTable - pub fn construct(meta: &mut ConstraintSystem) -> Self { + pub fn construct(meta: &mut ConstraintSystem) -> Self { Self { rw_counter: meta.advice_column(), is_write: meta.advice_column(), @@ -611,7 +610,7 @@ impl LookupTable for MptTable { impl MptTable { /// Construct a new MptTable - pub(crate) fn construct(meta: &mut ConstraintSystem) -> Self { + pub(crate) fn construct(meta: &mut ConstraintSystem) -> Self { Self([ meta.advice_column(), // Address meta.advice_column_in(SecondPhase), // Storage key @@ -716,7 +715,7 @@ impl BytecodeTable { || "bytecode table all-zero row", column, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; } offset += 1; @@ -825,7 +824,7 @@ impl BlockTable { || "block table all-zero row", column, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; } offset += 1; @@ -927,7 +926,7 @@ impl KeccakTable { }); vec![[ - Value::known(F::one()), + Value::known(F::ONE), input_rlc, Value::known(input_len), output_rlc, @@ -967,7 +966,7 @@ impl KeccakTable { || "keccak table all-zero row", column, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; } offset += 1; @@ -1079,9 +1078,9 @@ impl CopyTable { .keccak_input() .map(|keccak_input| rlc::value(values.iter().rev(), keccak_input)) } else { - Value::known(F::zero()) + Value::known(F::ZERO) }; - let mut value_acc = Value::known(F::zero()); + let mut value_acc = Value::known(F::ZERO); for (step_idx, (is_read_step, copy_step)) in copy_event .bytes .iter() @@ -1107,12 +1106,12 @@ impl CopyTable { .enumerate() { // is_first - let is_first = Value::known(if step_idx == 0 { F::one() } else { F::zero() }); + let is_first = Value::known(if step_idx == 0 { F::ONE } else { F::ZERO }); // is last let is_last = if step_idx == copy_event.bytes.len() * 2 - 1 { - Value::known(F::one()) + Value::known(F::ONE) } else { - Value::known(F::zero()) + Value::known(F::ZERO) }; // id @@ -1167,11 +1166,11 @@ impl CopyTable { }; // is_pad let is_pad = Value::known(F::from( - is_read_step && copy_step_addr >= copy_event.src_addr_end, + (is_read_step && copy_step_addr >= copy_event.src_addr_end) as u64, )); // is_code - let is_code = Value::known(copy_step.is_code.map_or(F::zero(), |v| F::from(v))); + let is_code = Value::known(copy_step.is_code.map_or(F::ZERO, |v| F::from(v as u64))); assignments.push(( tag, @@ -1221,7 +1220,7 @@ impl CopyTable { || "copy table all-zero row", column, offset, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; } offset += 1; @@ -1336,9 +1335,9 @@ impl ExpTable { let mut exponent = exp_event.exponent; for (step_idx, exp_step) in exp_event.steps.iter().rev().enumerate() { let is_last = if step_idx == exp_event.steps.len() - 1 { - F::one() + F::ONE } else { - F::zero() + F::ZERO }; let (exp_lo, exp_hi) = split_u256(&exp_step.d); let (exponent_lo, exponent_hi) = split_u256(&exponent); @@ -1358,7 +1357,7 @@ impl ExpTable { // row 2 assignments.push([ identifier, - F::zero(), + F::ZERO, base_limbs[1].as_u64().into(), exponent_hi .to_scalar() @@ -1370,21 +1369,21 @@ impl ExpTable { // row 3 assignments.push([ identifier, - F::zero(), + F::ZERO, base_limbs[2].as_u64().into(), - F::zero(), - F::zero(), + F::ZERO, + F::ZERO, ]); // row 4 assignments.push([ identifier, - F::zero(), + F::ZERO, base_limbs[3].as_u64().into(), - F::zero(), - F::zero(), + F::ZERO, + F::ZERO, ]); for _ in ROWS_PER_STEP..OFFSET_INCREMENT { - assignments.push([F::zero(), F::zero(), F::zero(), F::zero(), F::zero()]); + assignments.push([F::ZERO, F::ZERO, F::ZERO, F::ZERO, F::ZERO]); } // update intermediate exponent. @@ -1422,9 +1421,9 @@ impl ExpTable { )?; } let is_step = if offset % OFFSET_INCREMENT == 0 { - F::one() + F::ONE } else { - F::zero() + F::ZERO }; region.assign_fixed( || format!("exponentiation table row {}", offset), diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs index a21987bcbb..ffd60993aa 100644 --- a/zkevm-circuits/src/tx_circuit.rs +++ b/zkevm-circuits/src/tx_circuit.rs @@ -189,7 +189,7 @@ impl TxCircuit { 0, TxFieldTag::Null, 0, - Value::known(F::zero()), + Value::known(F::ZERO), )?; offset += 1; // Assign al Tx fields except for call data @@ -221,7 +221,10 @@ impl TxCircuit { TxFieldTag::CalleeAddress, Value::known(tx.to_or_zero().to_scalar().expect("tx.to too big")), ), - (TxFieldTag::IsCreate, Value::known(F::from(tx.is_create()))), + ( + TxFieldTag::IsCreate, + Value::known(F::from(tx.is_create() as u64)), + ), ( TxFieldTag::Value, challenges @@ -285,7 +288,7 @@ impl TxCircuit { 0, // tx_id TxFieldTag::CallData, 0, - Value::known(F::zero()), + Value::known(F::ZERO), )?; offset += 1; } diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index 64f2bfb171..25dc38022d 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -17,9 +17,10 @@ use eth_types::{ Field, }; use halo2_proofs::{ - arithmetic::{CurveAffine, FieldExt}, + arithmetic::CurveAffine, circuit::{AssignedCell, Cell, Layouter, Value}, halo2curves::{ + ff::PrimeField, group::{Curve, Group}, secp256k1, secp256k1::Secp256k1Affine, @@ -67,7 +68,7 @@ impl SignVerifyChip { ::CurveExt::random(&mut rng).to_affine(); Self { aux_generator, - window_size: 2, + window_size: 4, max_verif, _marker: PhantomData, } @@ -86,7 +87,7 @@ impl SignVerifyChip { // region. TODO: Figure out a way to get these numbers automatically. let rows_range_chip_table = 295188; let rows_ecc_chip_aux = 226; - let rows_ecdsa_chip_verification = 140360; + let rows_ecdsa_chip_verification = 104471; let rows_signature_address_verify = 76; std::cmp::max( rows_range_chip_table, @@ -100,7 +101,7 @@ impl Default for SignVerifyChip { fn default() -> Self { Self { aux_generator: Secp256k1Affine::default(), - window_size: 1, + window_size: 4, max_verif: 0, _marker: PhantomData::default(), } @@ -314,7 +315,7 @@ pub(crate) struct AssignedSignatureVerify { // Return an array of bytes that corresponds to the little endian representation // of the integer, adding the constraints to verify the correctness of the // conversion (byte range check included). -fn integer_to_bytes_le( +fn integer_to_bytes_le( ctx: &mut RegionCtx<'_, F>, range_chip: &RangeChip, int: &AssignedInteger, @@ -352,7 +353,7 @@ impl SignVerifyChip { ecc_chip: &mut GeneralEccChip, ) -> Result<(), Error> { ecc_chip.assign_aux_generator(ctx, Value::known(self.aux_generator))?; - ecc_chip.assign_aux(ctx, self.window_size, 1)?; + ecc_chip.assign_aux(ctx, self.window_size, 2)?; Ok(()) } @@ -426,15 +427,15 @@ impl SignVerifyChip { challenge: Value, inputs_le: impl IntoIterator>, ) -> Result, Error> { - let zero = chips.main_gate.assign_constant(ctx, F::zero())?; + let zero = chips.main_gate.assign_constant(ctx, F::ZERO)?; let columns = config.main_gate_config.advices(); let inputs_le = inputs_le.into_iter().collect_vec(); - let inputs_be = iter::repeat_with(|| Term::assigned(zero.cell(), Value::known(F::zero()))) + let inputs_be = iter::repeat_with(|| Term::assigned(zero.cell(), Value::known(F::ZERO))) .take(Integer::next_multiple_of(&inputs_le.len(), &columns.len()) - inputs_le.len()) .chain(inputs_le.into_iter().rev()) .collect_vec(); - let mut rlc = Value::known(F::zero()); + let mut rlc = Value::known(F::ZERO); for (chunk_idx, chunk) in inputs_be.chunks_exact(columns.len()).enumerate() { ctx.enable(q_rlc)?; let assigned_rlc = ctx.assign_advice(|| "{name}_rlc[{chunk_idx}]", config.rlc, rlc)?; @@ -450,9 +451,7 @@ impl SignVerifyChip { } rlc = iter::once(rlc) .chain(chunk.iter().map(|term| term.value())) - .fold(Value::known(F::zero()), |acc, input| { - acc * challenge + input - }); + .fold(Value::known(F::ZERO), |acc, input| acc * challenge + input); ctx.next(); } @@ -519,17 +518,15 @@ impl SignVerifyChip { // Ref. spec SignVerifyChip 2. Verify that the first 20 bytes of the // pub_key_hash equal the address let (address, pk_hash_lo) = { - let powers_of_256 = - iter::successors(Some(F::one()), |coeff| Some(F::from(256) * coeff)) - .take(20) - .collect_vec(); + let powers_of_256 = iter::successors(Some(F::ONE), |coeff| Some(F::from(256) * coeff)) + .take(20) + .collect_vec(); let terms = pk_hash[12..] .iter() .zip(powers_of_256.into_iter().rev()) .map(|(byte, coeff)| maingate::Term::Unassigned(*byte, coeff)) .collect_vec(); - let (address, pk_hash_lo) = - main_gate.decompose(ctx, &terms, F::zero(), |_, _| Ok(()))?; + let (address, pk_hash_lo) = main_gate.decompose(ctx, &terms, F::ZERO, |_, _| Ok(()))?; ( address, @@ -545,7 +542,7 @@ impl SignVerifyChip { // Ref. spec SignVerifyChip 3. Verify that the signed message in the ecdsa_chip // with RLC encoding corresponds to msg_hash_rlc let msg_hash_rlc = { - let zero = main_gate.assign_constant(ctx, F::zero())?; + let zero = main_gate.assign_constant(ctx, F::ZERO)?; let assigned_msg_hash_le = assigned_ecdsa .msg_hash_le .iter() @@ -700,7 +697,7 @@ impl SignVerifyChip { fn pub_key_hash_to_address(pk_hash: &[u8]) -> F { pk_hash[32 - 20..] .iter() - .fold(F::zero(), |acc, b| acc * F::from(256) + F::from(*b as u64)) + .fold(F::ZERO, |acc, b| acc * F::from(256) + F::from(*b as u64)) } #[cfg(test)] @@ -797,7 +794,7 @@ mod sign_verify_tests { let circuit = TestCircuitSignVerify:: { sign_verify: SignVerifyChip { aux_generator, - window_size: 2, + window_size: 4, max_verif, _marker: PhantomData, }, diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index 3c0f591bdb..b48555a3e4 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -1,7 +1,6 @@ //! Common utility traits and functions. use bus_mapping::evm::OpcodeId; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Layouter, Value}, plonk::{ Challenge, Circuit, ConstraintSystem, Error, Expression, FirstPhase, SecondPhase, @@ -15,7 +14,7 @@ use eth_types::{Field, ToAddress, Word}; pub use ethers_core::types::{Address, U256}; pub use gadgets::util::Expr; -pub(crate) fn query_expression( +pub(crate) fn query_expression( meta: &mut ConstraintSystem, mut f: impl FnMut(&mut VirtualCells) -> T, ) -> T { @@ -27,7 +26,7 @@ pub(crate) fn query_expression( expr.unwrap() } -pub(crate) fn random_linear_combine_word(bytes: [u8; 32], randomness: F) -> F { +pub(crate) fn random_linear_combine_word(bytes: [u8; 32], randomness: F) -> F { rlc::value(&bytes, randomness) } @@ -41,7 +40,7 @@ pub struct Challenges { impl Challenges { /// Construct `Challenges` by allocating challenges in specific phases. - pub fn construct(meta: &mut ConstraintSystem) -> Self { + pub fn construct(meta: &mut ConstraintSystem) -> Self { #[cfg(any(feature = "test", test, feature = "test-circuits"))] let _dummy_cols = [ meta.advice_column(), @@ -57,7 +56,7 @@ impl Challenges { } /// Returns `Expression` of challenges from `ConstraintSystem`. - pub fn exprs(&self, meta: &mut ConstraintSystem) -> Challenges> { + pub fn exprs(&self, meta: &mut ConstraintSystem) -> Challenges> { let [evm_word, keccak_input, lookup_input] = query_expression(meta, |meta| { [self.evm_word, self.keccak_input, self.lookup_input] .map(|challenge| meta.query_challenge(challenge)) @@ -70,7 +69,7 @@ impl Challenges { } /// Returns `Value` of challenges from `Layouter`. - pub fn values(&self, layouter: &mut impl Layouter) -> Challenges> { + pub fn values(&self, layouter: &mut impl Layouter) -> Challenges> { Challenges { evm_word: layouter.get_challenge(self.evm_word), keccak_input: layouter.get_challenge(self.keccak_input), diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index d65db2c434..a8f52d822e 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -2,8 +2,11 @@ use std::collections::HashMap; #[cfg(any(feature = "test", test))] use crate::evm_circuit::{detect_fixed_table_tags, EvmCircuit}; +#[cfg(feature = "test")] +use crate::util::SubCircuit; + +use crate::{evm_circuit::util::rlc, table::BlockContextFieldTag}; -use crate::{evm_circuit::util::rlc, table::BlockContextFieldTag, util::SubCircuit}; use bus_mapping::{ circuit_input_builder::{self, CircuitsParams, CopyEvent, ExpEvent}, Error, @@ -158,39 +161,39 @@ impl BlockContext { vec![ [ Value::known(F::from(BlockContextFieldTag::Coinbase as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(self.coinbase.to_scalar().unwrap()), ], [ Value::known(F::from(BlockContextFieldTag::Timestamp as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(self.timestamp.to_scalar().unwrap()), ], [ Value::known(F::from(BlockContextFieldTag::Number as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(self.number.to_scalar().unwrap()), ], [ Value::known(F::from(BlockContextFieldTag::Difficulty as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), randomness .map(|randomness| rlc::value(&self.difficulty.to_le_bytes(), randomness)), ], [ Value::known(F::from(BlockContextFieldTag::GasLimit as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(F::from(self.gas_limit)), ], [ Value::known(F::from(BlockContextFieldTag::BaseFee as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), randomness .map(|randomness| rlc::value(&self.base_fee.to_le_bytes(), randomness)), ], [ Value::known(F::from(BlockContextFieldTag::ChainId as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), randomness .map(|randomness| rlc::value(&self.chain_id.to_le_bytes(), randomness)), ], diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs index 75345c45b2..4e945dc380 100644 --- a/zkevm-circuits/src/witness/bytecode.rs +++ b/zkevm-circuits/src/witness/bytecode.rs @@ -35,8 +35,8 @@ impl Bytecode { rows.push([ hash, Value::known(F::from(BytecodeFieldTag::Header as u64)), - Value::known(F::zero()), - Value::known(F::zero()), + Value::known(F::ZERO), + Value::known(F::ZERO), Value::known(F::from(self.bytes.len() as u64)), ]); diff --git a/zkevm-circuits/src/witness/mpt.rs b/zkevm-circuits/src/witness/mpt.rs index dc9cc6bffb..c415feb419 100644 --- a/zkevm-circuits/src/witness/mpt.rs +++ b/zkevm-circuits/src/witness/mpt.rs @@ -188,7 +188,7 @@ impl Key { } fn storage_key(&self, randomness: F) -> F { match self { - Self::Account { .. } => F::zero(), + Self::Account { .. } => F::ZERO, Self::AccountStorage { storage_key, .. } => { rlc::value(&storage_key.to_le_bytes(), randomness) } diff --git a/zkevm-circuits/src/witness/rw.rs b/zkevm-circuits/src/witness/rw.rs index 27999b8b27..994c3c3194 100644 --- a/zkevm-circuits/src/witness/rw.rs +++ b/zkevm-circuits/src/witness/rw.rs @@ -281,7 +281,7 @@ impl RwRow { values .iter() .rev() - .fold(F::zero(), |acc, value| acc * randomness + value) + .fold(F::ZERO, |acc, value| acc * randomness + value) } pub(crate) fn rlc_value(&self, randomness: Value) -> Value { @@ -399,7 +399,7 @@ impl Rw { ), value: self.value_assignment(randomness), value_prev: self.value_prev_assignment(randomness).unwrap_or_default(), - aux1: F::zero(), // only used for AccountStorage::tx_id, which moved to key1. + aux1: F::ZERO, // only used for AccountStorage::tx_id, which moved to key1. aux2: self .committed_value_assignment(randomness) .unwrap_or_default(), @@ -423,8 +423,8 @@ impl Rw { value: randomness.map(|randomness| self.value_assignment(randomness)), value_prev: randomness .map(|randomness| self.value_prev_assignment(randomness).unwrap_or_default()), - aux1: Value::known(F::zero()), /* only used for AccountStorage::tx_id, which moved to - * key1. */ + aux1: Value::known(F::ZERO), /* only used for AccountStorage::tx_id, which moved to + * key1. */ aux2: randomness.map(|randomness| { self.committed_value_assignment(randomness) .unwrap_or_default() @@ -563,7 +563,7 @@ impl Rw { pub(crate) fn value_assignment(&self, randomness: F) -> F { match self { - Self::Start { .. } => F::zero(), + Self::Start { .. } => F::ZERO, Self::CallContext { field_tag, value, .. } => { diff --git a/zkevm-circuits/src/witness/tx.rs b/zkevm-circuits/src/witness/tx.rs index 9c0475cce6..a6119f12fd 100644 --- a/zkevm-circuits/src/witness/tx.rs +++ b/zkevm-circuits/src/witness/tx.rs @@ -48,19 +48,19 @@ impl Transaction { [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::Nonce as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(F::from(self.nonce)), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::Gas as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(F::from(self.gas)), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::GasPrice as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), challenges .evm_word() .map(|challenge| rlc::value(&self.gas_price.to_le_bytes(), challenge)), @@ -68,25 +68,25 @@ impl Transaction { [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CallerAddress as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(self.caller_address.to_scalar().unwrap()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CalleeAddress as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(self.callee_address.to_scalar().unwrap()), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::IsCreate as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(F::from(self.is_create as u64)), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::Value as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), challenges .evm_word() .map(|challenge| rlc::value(&self.value.to_le_bytes(), challenge)), @@ -94,13 +94,13 @@ impl Transaction { [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CallDataLength as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(F::from(self.call_data_length as u64)), ], [ Value::known(F::from(self.id as u64)), Value::known(F::from(TxContextFieldTag::CallDataGasCost as u64)), - Value::known(F::zero()), + Value::known(F::ZERO), Value::known(F::from(self.call_data_gas_cost)), ], ]; From 82c794269a5f9a4e78517c95f2b947e3418e7524 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 5 May 2023 15:11:18 +0800 Subject: [PATCH 029/102] LookupTable --- zkevm-circuits/src/circuit_tools/table.rs | 69 +++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 zkevm-circuits/src/circuit_tools/table.rs diff --git a/zkevm-circuits/src/circuit_tools/table.rs b/zkevm-circuits/src/circuit_tools/table.rs new file mode 100644 index 0000000000..2d42d67c61 --- /dev/null +++ b/zkevm-circuits/src/circuit_tools/table.rs @@ -0,0 +1,69 @@ +use eth_types::Field; +use halo2_proofs::{ + circuit::Region, + plonk::{Advice, Column, ConstraintSystem, *}, + poly::Rotation, +}; +use std::fmt::Debug; +use std::hash::Hash; + +/// Trait used to define lookup tables +pub trait LookupTable: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash + { + /// Returns the list of ALL the table columns following the table order. + fn columns(&self) -> Vec>; + + /// Returns the list of ALL the table advice columns following the table + /// order. + fn advice_columns(&self) -> Vec> { + self.columns() + .iter() + .map(|&col| col.try_into()) + .filter_map(|res| res.ok()) + .collect() + } + + /// Returns the String annotations associated to each column of the table. + fn annotations(&self) -> Vec; + + /// Return the list of expressions used to define the lookup table. + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + self.columns() + .iter() + .map(|&column| meta.query_any(column, Rotation::cur())) + .collect() + } + + /// Annotates a lookup table by passing annotations for each of it's + /// columns. + fn annotate_columns(&self, cs: &mut ConstraintSystem) { + self.columns() + .iter() + .zip(self.annotations().iter()) + .for_each(|(&col, ann)| cs.annotate_lookup_any_column(col, || ann)) + } + + /// Annotates columns of a table embedded within a circuit region. + fn annotate_columns_in_region(&self, region: &mut Region) { + self.columns() + .iter() + .zip(self.annotations().iter()) + .for_each(|(&col, ann)| region.name_column(|| ann, col)) + } +} + +impl> + Copy, const W: usize> LookupTable for [C; W] { + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + self.iter() + .map(|column| meta.query_any(*column, Rotation::cur())) + .collect() + } + + fn columns(&self) -> Vec> { + self.iter().map(|&col| col.into()).collect() + } + + fn annotations(&self) -> Vec { + vec![] + } +} \ No newline at end of file From a43f688bb55345b28fe7c9a5c110e894d19c1838 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 5 May 2023 16:34:49 +0800 Subject: [PATCH 030/102] cargo fix --- zkevm-circuits/src/circuit_tools/cell_manager.rs | 2 +- zkevm-circuits/src/circuit_tools/gadgets.rs | 1 - zkevm-circuits/src/mpt_circuit.rs | 6 +++--- zkevm-circuits/src/mpt_circuit/account_leaf.rs | 2 +- zkevm-circuits/src/mpt_circuit/branch.rs | 3 +-- zkevm-circuits/src/mpt_circuit/extension.rs | 3 +-- zkevm-circuits/src/mpt_circuit/extension_branch.rs | 1 - zkevm-circuits/src/mpt_circuit/helpers.rs | 6 +++--- zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs | 6 +++--- zkevm-circuits/src/mpt_circuit/start.rs | 4 ++-- zkevm-circuits/src/mpt_circuit/storage_leaf.rs | 2 +- 11 files changed, 16 insertions(+), 20 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index 49fa89402a..e5c897932f 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -145,7 +145,7 @@ impl CustomTable for TestTable { } } -fn works_like_this(table: TestTable, config: &[(TestTable, usize)]) { +fn works_like_this(table: TestTable, _config: &[(TestTable, usize)]) { if table.matches_to(&TestTable::Fixed) { println!("matched"); } diff --git a/zkevm-circuits/src/circuit_tools/gadgets.rs b/zkevm-circuits/src/circuit_tools/gadgets.rs index 7ed55c8abe..cea2053487 100644 --- a/zkevm-circuits/src/circuit_tools/gadgets.rs +++ b/zkevm-circuits/src/circuit_tools/gadgets.rs @@ -2,7 +2,6 @@ use eth_types::Field; use gadgets::util::Expr; use halo2_proofs::{ - circuit::{Region, Value}, plonk::{Error, Expression}, }; diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 989c2024db..5f72385693 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -33,7 +33,7 @@ use self::{ use crate::{ assign, assignf, circuit, circuit_tools::{ - cell_manager::CellManager, constraint_builder::ConstraintBuilder, memory::Memory, + constraint_builder::ConstraintBuilder, memory::Memory, cached_region::CachedRegion, }, mpt_circuit::{ @@ -561,7 +561,7 @@ impl Circuit for MPTCircuit { // let challenges_expr = challenges.exprs(meta); let r = 2u64; - let challenges = Challenges::mock( + let _challenges = Challenges::mock( Value::known(F::from(r)), Value::known(F::from(r)), Value::known(F::from(r)), @@ -584,7 +584,7 @@ impl Circuit for MPTCircuit { fn synthesize( &self, - (config, challenges): Self::Config, + (config, _challenges): Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { // let challenges = challenges.values(&mut layouter); diff --git a/zkevm-circuits/src/mpt_circuit/account_leaf.rs b/zkevm-circuits/src/mpt_circuit/account_leaf.rs index f09f455060..ab1e4daa6f 100644 --- a/zkevm-circuits/src/mpt_circuit/account_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/account_leaf.rs @@ -1,7 +1,7 @@ use eth_types::Field; use gadgets::util::{pow, Scalar}; use halo2_proofs::{ - circuit::{Region, Value}, + circuit::{Value}, plonk::{Error, VirtualCells}, poly::Rotation, }; diff --git a/zkevm-circuits/src/mpt_circuit/branch.rs b/zkevm-circuits/src/mpt_circuit/branch.rs index 3afc687372..85569e191d 100644 --- a/zkevm-circuits/src/mpt_circuit/branch.rs +++ b/zkevm-circuits/src/mpt_circuit/branch.rs @@ -1,7 +1,6 @@ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - circuit::Region, plonk::{Error, Expression, VirtualCells}, }; @@ -273,7 +272,7 @@ impl BranchGadget { pub(crate) fn assign( &self, region: &mut CachedRegion<'_, '_, F>, - mpt_config: &MPTConfig, + _mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, is_placeholder: &[bool; 2], diff --git a/zkevm-circuits/src/mpt_circuit/extension.rs b/zkevm-circuits/src/mpt_circuit/extension.rs index 4656b26df3..972a5e3830 100644 --- a/zkevm-circuits/src/mpt_circuit/extension.rs +++ b/zkevm-circuits/src/mpt_circuit/extension.rs @@ -1,7 +1,6 @@ use eth_types::Field; use gadgets::util::{pow, Scalar}; use halo2_proofs::{ - circuit::Region, plonk::{Error, Expression, VirtualCells}, }; @@ -182,7 +181,7 @@ impl ExtensionGadget { pub(crate) fn assign( &self, region: &mut CachedRegion<'_, '_, F>, - mpt_config: &MPTConfig, + _mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, key_data: &KeyDataWitness, diff --git a/zkevm-circuits/src/mpt_circuit/extension_branch.rs b/zkevm-circuits/src/mpt_circuit/extension_branch.rs index 669f137c03..ac1f329418 100644 --- a/zkevm-circuits/src/mpt_circuit/extension_branch.rs +++ b/zkevm-circuits/src/mpt_circuit/extension_branch.rs @@ -1,7 +1,6 @@ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - circuit::Region, plonk::{Error, VirtualCells}, }; diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index 701841f4ea..18573df644 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -1,7 +1,7 @@ use crate::{ assign, circuit, circuit_tools::{ - cell_manager::{Cell, CellManager, CustomTable}, + cell_manager::{Cell, CellManager}, constraint_builder::{ ConstraintBuilder, RLCChainable, RLCChainableValue, RLCable, RLCableValue, }, @@ -18,7 +18,7 @@ use crate::{ use eth_types::Field; use gadgets::util::{or, pow, Scalar}; use halo2_proofs::{ - plonk::{Error, Expression, VirtualCells}, circuit::Value, + plonk::{Error, Expression, VirtualCells}, }; use super::{ @@ -757,7 +757,7 @@ pub(crate) fn ext_key_rlc_value( // Returns the number of nibbles stored in a key value pub(crate) mod num_nibbles { - use crate::{_cb, circuit, circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::CustomTable}, mpt_circuit::table::Table}; + use crate::{circuit, circuit_tools::{constraint_builder::ConstraintBuilder}, mpt_circuit::table::Table}; use eth_types::Field; use halo2_proofs::plonk::Expression; diff --git a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs index 5b0ecef57a..920f3bec4a 100644 --- a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs +++ b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs @@ -1,9 +1,9 @@ -use std::marker::PhantomData; + use crate::{ - _cb, circuit, + circuit, circuit_tools::{ - cell_manager::{Cell, CustomTable}, + cell_manager::{Cell}, constraint_builder::{ConstraintBuilder, RLCable, RLCableValue}, cached_region::CachedRegion, }, matchw, diff --git a/zkevm-circuits/src/mpt_circuit/start.rs b/zkevm-circuits/src/mpt_circuit/start.rs index 48632332d0..d8511ccb75 100644 --- a/zkevm-circuits/src/mpt_circuit/start.rs +++ b/zkevm-circuits/src/mpt_circuit/start.rs @@ -19,7 +19,7 @@ use crate::{ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - plonk::{Error, VirtualCells}, circuit::Value, + plonk::{Error, VirtualCells}, }; #[derive(Clone, Debug, Default)] @@ -84,7 +84,7 @@ impl StartConfig { pub fn assign( &self, region: &mut CachedRegion<'_, '_, F>, - ctx: &MPTConfig, + _ctx: &MPTConfig, pv: &mut MPTState, offset: usize, node: &Node, diff --git a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs index 8757c69b26..61c5838bc9 100644 --- a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs @@ -1,7 +1,7 @@ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - circuit::{Region, Value}, + circuit::{Value}, plonk::{Error, VirtualCells}, poly::Rotation, }; From 6d0e84f16af91f8fca75f1815f4feb8f3c246224 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Sat, 6 May 2023 20:32:48 +0800 Subject: [PATCH 031/102] change to TableType, dynamically generate phase config according to LookupTable --- zkevm-circuits/src/circuit_tools.rs | 1 + .../src/circuit_tools/cached_region.rs | 8 +-- .../src/circuit_tools/cell_manager.rs | 68 +++++++++++-------- .../src/circuit_tools/constraint_builder.rs | 10 +-- zkevm-circuits/src/circuit_tools/gadgets.rs | 8 +-- zkevm-circuits/src/circuit_tools/memory.rs | 14 ++-- zkevm-circuits/src/circuit_tools/table.rs | 23 +++++-- .../evm_circuit/util/math_gadget/test_util.rs | 2 +- zkevm-circuits/src/mpt_circuit.rs | 7 +- zkevm-circuits/src/mpt_circuit/table.rs | 38 +++++++++-- zkevm-circuits/src/table.rs | 4 +- 11 files changed, 117 insertions(+), 66 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools.rs b/zkevm-circuits/src/circuit_tools.rs index 02270ce17c..7b736a3644 100644 --- a/zkevm-circuits/src/circuit_tools.rs +++ b/zkevm-circuits/src/circuit_tools.rs @@ -6,3 +6,4 @@ pub mod cell_manager; pub mod cached_region; pub mod gadgets; pub mod memory; +pub mod table; \ No newline at end of file diff --git a/zkevm-circuits/src/circuit_tools/cached_region.rs b/zkevm-circuits/src/circuit_tools/cached_region.rs index d388ae0b5a..1fa2b27eb7 100644 --- a/zkevm-circuits/src/circuit_tools/cached_region.rs +++ b/zkevm-circuits/src/circuit_tools/cached_region.rs @@ -14,7 +14,7 @@ use std::{ hash::{Hash, Hasher}, }; -use super::cell_manager::CustomTable; +use super::cell_manager::TableType; pub struct CachedRegion<'r, 'b, F: Field> { region: &'r mut Region<'b, F>, @@ -162,7 +162,7 @@ impl<'r, 'b, F: Field> CachedRegion<'r, 'b, F> { } #[derive(Debug, Clone)] -pub struct StoredExpression { +pub struct StoredExpression { pub(crate) name: String, cell: Cell, cell_type: CellType_, @@ -170,14 +170,14 @@ pub struct StoredExpression { expr_id: String, } -impl Hash for StoredExpression { +impl Hash for StoredExpression { fn hash(&self, state: &mut H) { self.expr_id.hash(state); self.cell_type.hash(state); } } -impl StoredExpression { +impl StoredExpression { pub fn assign( &self, region: &mut CachedRegion<'_, '_, F>, diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index e5c897932f..f5aa438cf5 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -1,6 +1,6 @@ //! Cell manager use crate::util::{Expr, query_expression}; -use crate::circuit_tools::cached_region::CachedRegion; +use crate::circuit_tools::{table::LookupTable, cached_region::CachedRegion}; use eth_types::Field; use halo2_proofs::{ @@ -114,7 +114,7 @@ impl Expr for &Cell { // } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) enum CellType_ { +pub(crate) enum CellType_ { StoragePhase1, StoragePhase2, StoragePermutation, @@ -122,37 +122,28 @@ pub(crate) enum CellType_ { Lookup(T), } -pub trait CustomTable: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash{ - fn matches_to(&self, other: &Self) -> bool; -} +pub trait TableType: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash {} -/// Example #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] -pub(crate) enum TestTable { - Fixed, - Tx, - Rw, - Bytecode, - Block, - Copy, - Keccak, - Exp, +pub enum DefaultTableType { + Default, } -impl CustomTable for TestTable { - fn matches_to(&self, other: &Self) -> bool { - self == other - } -} +impl TableType for DefaultTableType {} +/// Example -fn works_like_this(table: TestTable, _config: &[(TestTable, usize)]) { - if table.matches_to(&TestTable::Fixed) { - println!("matched"); - } -} +// use super::table::{TestTableType, MptTable, BytecodeTable}; + +// fn work_like_this(meta: &mut ConstraintSystem) { +// let config: PhaseConfig = PhaseConfig::new( +// &[MptTable::construct(meta), BytecodeTable::construct(meta)], +// 2, +// 3 +// ); +// } -impl CellType_ { +impl CellType_ { // The phase that given `Expression` becomes evaluateable. fn expr_phase(expr: &Expression) -> u8 { use Expression::*; @@ -181,21 +172,21 @@ impl CellType_ { } #[derive(Clone, Debug)] -pub(crate) struct CellColumn { +pub(crate) struct CellColumn { index: usize, cell_type: CellType_, height: usize, expr: Expression, } -impl Expr for CellColumn { +impl Expr for CellColumn { fn expr(&self) -> Expression { self.expr.clone() } } #[derive(Clone, Debug)] -pub struct CellManager { +pub struct CellManager { // Thoughts (Cecilia): Integrate CellManager's function into Halo2's VirtualCell // They do the same things by saving queried Exressions // CM is just slightly smarter. @@ -217,7 +208,24 @@ pub struct PhaseConfig { phase1: usize, // byte } -impl CellManager { +impl PhaseConfig { + pub fn new( + tables: Vec<&dyn LookupTable>, + phase2: usize, + phase1: usize + ) -> Self { + let phase3 = tables.iter().map(|t| + (t.get_type(), t.columns().len()) + ).collect::>(); + Self { + phase3, + phase2, + phase1, + } + } +} + +impl CellManager { pub(crate) fn new( meta: &mut ConstraintSystem, // meta只出现一次,new的时候把所有cover的cells都query一遍 height: usize, // 拿到 Expr 存起来,后面 cb.query_cell 直接给对应格子的 Expr diff --git a/zkevm-circuits/src/circuit_tools/constraint_builder.rs b/zkevm-circuits/src/circuit_tools/constraint_builder.rs index 2725e56aba..568a8a52a0 100644 --- a/zkevm-circuits/src/circuit_tools/constraint_builder.rs +++ b/zkevm-circuits/src/circuit_tools/constraint_builder.rs @@ -7,7 +7,7 @@ use gadgets::util::{and, sum, Scalar}; use halo2_proofs::plonk::{ConstraintSystem, Expression}; use itertools::Itertools; -use super::cell_manager::{Cell, CellManager, CellType_, CustomTable}; +use super::cell_manager::{Cell, CellManager, CellType_, TableType}; /// Lookup data #[derive(Clone)] @@ -24,7 +24,7 @@ pub struct LookupData { /// Constraint builder #[derive(Clone)] -pub struct ConstraintBuilder { +pub struct ConstraintBuilder { constraints: Vec<(&'static str, Expression)>, max_degree: usize, conditions: Vec>, @@ -36,7 +36,7 @@ pub struct ConstraintBuilder { pub cell_manager: Option>, } -impl ConstraintBuilder { +impl ConstraintBuilder { pub(crate) fn new(max_degree: usize, cell_manager: Option>) -> Self { ConstraintBuilder { constraints: Vec::new(), @@ -327,7 +327,7 @@ impl ConstraintBuilder { } } -pub(crate) fn merge_lookups( +pub(crate) fn merge_lookups( cb: &mut ConstraintBuilder, lookups: Vec>, ) -> (Expression, Vec>) { @@ -340,7 +340,7 @@ pub(crate) fn merge_lookups( ) } -pub(crate) fn merge_values( +pub(crate) fn merge_values( cb: &mut ConstraintBuilder, values: Vec<(Expression, Vec>)>, ) -> (Expression, Vec>) { diff --git a/zkevm-circuits/src/circuit_tools/gadgets.rs b/zkevm-circuits/src/circuit_tools/gadgets.rs index cea2053487..fbcf624881 100644 --- a/zkevm-circuits/src/circuit_tools/gadgets.rs +++ b/zkevm-circuits/src/circuit_tools/gadgets.rs @@ -7,7 +7,7 @@ use halo2_proofs::{ use crate::evm_circuit::util::{from_bytes, pow_of_two}; -use super::{cell_manager::{Cell, CustomTable}, constraint_builder::ConstraintBuilder, cached_region::CachedRegion}; +use super::{cell_manager::{Cell, TableType}, constraint_builder::ConstraintBuilder, cached_region::CachedRegion}; /// Returns `1` when `value == 0`, and returns `0` otherwise. #[derive(Clone, Debug, Default)] @@ -17,7 +17,7 @@ pub struct IsZeroGadget { } impl IsZeroGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, value: Expression) -> Self { + pub(crate) fn construct(cb: &mut ConstraintBuilder, value: Expression) -> Self { circuit!([meta, cb], { let inverse = cb.query_cell(); @@ -61,7 +61,7 @@ pub struct IsEqualGadget { } impl IsEqualGadget { - pub(crate) fn construct( + pub(crate) fn construct( cb: &mut ConstraintBuilder, lhs: Expression, rhs: Expression, @@ -104,7 +104,7 @@ pub struct LtGadget { } impl LtGadget { - pub(crate) fn construct( + pub(crate) fn construct( cb: &mut ConstraintBuilder, lhs: Expression, rhs: Expression, diff --git a/zkevm-circuits/src/circuit_tools/memory.rs b/zkevm-circuits/src/circuit_tools/memory.rs index a9a6910609..8e8f57e0f5 100644 --- a/zkevm-circuits/src/circuit_tools/memory.rs +++ b/zkevm-circuits/src/circuit_tools/memory.rs @@ -11,7 +11,7 @@ use std::{ ops::{Index, IndexMut}, }; -use super::{constraint_builder::ConstraintBuilder, cell_manager::CustomTable}; +use super::{constraint_builder::ConstraintBuilder, cell_manager::TableType}; #[derive(Clone, Debug, Default)] pub(crate) struct Memory { @@ -55,7 +55,7 @@ impl Memory { unreachable!() } - pub(crate) fn generate_constraints( + pub(crate) fn generate_constraints( &self, cb: &mut ConstraintBuilder, is_first_row: Expression, @@ -150,7 +150,7 @@ impl MemoryBank { self.cur.expr() } - pub(crate) fn load( + pub(crate) fn load( &self, description: &'static str, cb: &mut ConstraintBuilder, @@ -160,7 +160,7 @@ impl MemoryBank { self.load_with_key(description, cb, self.key() - offset, values); } - pub(crate) fn load_with_key( + pub(crate) fn load_with_key( &self, description: &'static str, cb: &mut ConstraintBuilder, @@ -170,7 +170,7 @@ impl MemoryBank { cb.lookup(description, self.tag(), self.insert_key(key, values)); } - pub(crate) fn store( + pub(crate) fn store( &self, cb: &mut ConstraintBuilder, values: &[Expression], @@ -180,7 +180,7 @@ impl MemoryBank { key } - pub(crate) fn store_with_key( + pub(crate) fn store_with_key( &self, cb: &mut ConstraintBuilder, key: Expression, @@ -202,7 +202,7 @@ impl MemoryBank { self.store_offsets.clear(); } - pub(crate) fn generate_constraints( + pub(crate) fn generate_constraints( &self, cb: &mut ConstraintBuilder, is_first_row: Expression, diff --git a/zkevm-circuits/src/circuit_tools/table.rs b/zkevm-circuits/src/circuit_tools/table.rs index 2d42d67c61..f2c65051af 100644 --- a/zkevm-circuits/src/circuit_tools/table.rs +++ b/zkevm-circuits/src/circuit_tools/table.rs @@ -4,12 +4,16 @@ use halo2_proofs::{ plonk::{Advice, Column, ConstraintSystem, *}, poly::Rotation, }; -use std::fmt::Debug; -use std::hash::Hash; + + +use super::{cell_manager::{TableType, DefaultTableType}}; /// Trait used to define lookup tables -pub trait LookupTable: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash - { +pub trait LookupTable { + + + fn get_type(&self) -> T; + /// Returns the list of ALL the table columns following the table order. fn columns(&self) -> Vec>; @@ -52,7 +56,13 @@ pub trait LookupTable: Clone + Copy + Debug + PartialEq + Eq + Partial } } -impl> + Copy, const W: usize> LookupTable for [C; W] { + +impl> + Copy, const W: usize> LookupTable for [C; W] { + + fn get_type(&self) -> DefaultTableType { + DefaultTableType::Default + } + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { self.iter() .map(|column| meta.query_any(*column, Rotation::cur())) @@ -66,4 +76,5 @@ impl> + Copy, const W: usize> LookupTable for [ fn annotations(&self) -> Vec { vec![] } -} \ No newline at end of file +} + diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs index 169b879112..cb0a2ad326 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs @@ -13,7 +13,7 @@ use crate::{ }, Advice, Column, Fixed, }, - table::LookupTable, + circuit_tools::table::LookupTable, util::Challenges, }; use eth_types::{Field, Word, U256}; diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 5f72385693..1bdd88ff1c 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -41,7 +41,8 @@ use crate::{ start::StartConfig, storage_leaf::StorageLeafConfig, }, - table::{KeccakTable, LookupTable, MPTProofType, MptTable}, + circuit_tools::{table::LookupTable, cell_manager::PhaseConfig}, + table::{KeccakTable, MPTProofType, MptTable}, util::Challenges, }; use extension_branch::ExtensionBranchConfig; @@ -213,11 +214,13 @@ impl MPTConfig { memory: memory.clone(), }; + let _phase_config = PhaseConfig::new::(vec![&keccak_table], 2, 2); + let mut cb = MPTConstraintBuilder::new(33 + 10, None); meta.create_gate("MPT", |meta| { circuit!([meta, cb.base], { // Populate lookup tables - require!(@"keccak" => >::advice_columns(&keccak_table).iter().map(|table| a!(table)).collect()); + require!(@"keccak" => >::advice_columns(&keccak_table).iter().map(|table| a!(table)).collect()); require!(@"fixed" => fixed_table.iter().map(|table| f!(table)).collect()); ifx!{f!(q_enable) => { diff --git a/zkevm-circuits/src/mpt_circuit/table.rs b/zkevm-circuits/src/mpt_circuit/table.rs index e32176dc75..ef733c0ea8 100644 --- a/zkevm-circuits/src/mpt_circuit/table.rs +++ b/zkevm-circuits/src/mpt_circuit/table.rs @@ -1,6 +1,12 @@ +use eth_types::Field; +use halo2_proofs::plonk::{Column, Any}; use strum_macros::EnumIter; -use crate::circuit_tools::cell_manager::CustomTable; +use crate::{ + circuit_tools::cell_manager::TableType, + circuit_tools::table::LookupTable, + table::KeccakTable +}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] pub enum Table { @@ -14,8 +20,30 @@ pub enum Table { Exp, } -impl CustomTable for Table { - fn matches_to(&self, other: &Self) -> bool { - self == other +impl TableType for Table {} + +impl LookupTable for KeccakTable { + + fn get_type(&self) -> Table { + Table::Keccak + } + + fn columns(&self) -> Vec> { + vec![ + self.is_enabled.into(), + self.input_rlc.into(), + self.input_len.into(), + self.output_rlc.into(), + ] } -} \ No newline at end of file + + fn annotations(&self) -> Vec { + vec![ + String::from("is_enabled"), + String::from("input_rlc"), + String::from("input_len"), + String::from("output_rlc"), + ] + } + +} diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 9667bcc2ae..74a6340d4d 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -2,7 +2,7 @@ use crate::{ circuit, - circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::CustomTable, cached_region::CachedRegion}, + circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::TableType, cached_region::CachedRegion}, copy_circuit::number_or_hash_to_field, evm_circuit::util::rlc, exp_circuit::{OFFSET_INCREMENT, ROWS_PER_STEP}, @@ -657,7 +657,7 @@ impl MptTable { } } - pub(crate) fn constrain( + pub(crate) fn constrain( &self, meta: &mut VirtualCells<'_, F>, cb: &mut ConstraintBuilder, From 4ee4a27d50961a663489d38b339e40ff910b6ad9 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Tue, 9 May 2023 18:31:46 +0800 Subject: [PATCH 032/102] circuit tools & test: --- zkevm-circuits/src/circuit_tools.rs | 5 +- .../src/circuit_tools/cell_manager.rs | 5 +- zkevm-circuits/src/circuit_tools/table.rs | 8 +- zkevm-circuits/src/circuit_tools/tests.rs | 1 + .../src/circuit_tools/tests/util.rs | 123 ++++++++++++++++++ 5 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 zkevm-circuits/src/circuit_tools/tests.rs create mode 100644 zkevm-circuits/src/circuit_tools/tests/util.rs diff --git a/zkevm-circuits/src/circuit_tools.rs b/zkevm-circuits/src/circuit_tools.rs index 7b736a3644..06a1b88bba 100644 --- a/zkevm-circuits/src/circuit_tools.rs +++ b/zkevm-circuits/src/circuit_tools.rs @@ -6,4 +6,7 @@ pub mod cell_manager; pub mod cached_region; pub mod gadgets; pub mod memory; -pub mod table; \ No newline at end of file +pub mod table; + +#[cfg(test)] +mod tests; \ No newline at end of file diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index f5aa438cf5..c6850a6f7c 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -125,11 +125,10 @@ pub(crate) enum CellType_ { pub trait TableType: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash {} #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] -pub enum DefaultTableType { +pub enum SingleTable { Default, } - -impl TableType for DefaultTableType {} +impl TableType for SingleTable {} /// Example // use super::table::{TestTableType, MptTable, BytecodeTable}; diff --git a/zkevm-circuits/src/circuit_tools/table.rs b/zkevm-circuits/src/circuit_tools/table.rs index f2c65051af..d72644663c 100644 --- a/zkevm-circuits/src/circuit_tools/table.rs +++ b/zkevm-circuits/src/circuit_tools/table.rs @@ -6,7 +6,7 @@ use halo2_proofs::{ }; -use super::{cell_manager::{TableType, DefaultTableType}}; +use super::{cell_manager::{TableType, SingleTable}}; /// Trait used to define lookup tables pub trait LookupTable { @@ -57,10 +57,10 @@ pub trait LookupTable { } -impl> + Copy, const W: usize> LookupTable for [C; W] { +impl> + Copy, const W: usize> LookupTable for [C; W] { - fn get_type(&self) -> DefaultTableType { - DefaultTableType::Default + fn get_type(&self) -> SingleTable { + SingleTable::Default } fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { diff --git a/zkevm-circuits/src/circuit_tools/tests.rs b/zkevm-circuits/src/circuit_tools/tests.rs new file mode 100644 index 0000000000..344cb254de --- /dev/null +++ b/zkevm-circuits/src/circuit_tools/tests.rs @@ -0,0 +1 @@ +mod util; \ No newline at end of file diff --git a/zkevm-circuits/src/circuit_tools/tests/util.rs b/zkevm-circuits/src/circuit_tools/tests/util.rs new file mode 100644 index 0000000000..2ccbf53593 --- /dev/null +++ b/zkevm-circuits/src/circuit_tools/tests/util.rs @@ -0,0 +1,123 @@ +use std::vec; + +use crate::circuit_tools::cell_manager::{Cell, CellManager, PhaseConfig, SingleTable, TableType}; +use crate::circuit_tools::constraint_builder::ConstraintBuilder; +use crate::circuit_tools::memory::Memory; +use crate::util::{Expr, query_expression}; +use crate::circuit_tools::{table::LookupTable, cached_region::CachedRegion}; + +use eth_types::Field; +use gadgets::util::Scalar; +use halo2_proofs::plonk::Any; +use halo2_proofs::{ + circuit::{AssignedCell, Value}, + plonk::{ConstraintSystem, Advice, Column, Error, Expression, VirtualCells}, + poly::Rotation, +}; + + + +/// To Test: +/// 1. Constrain advices with cells +/// 2. Lookup (advices <--> advices) with cells (RAM) +/// 3. Lookup (advices <--> fixed) with cells (ROM) +/// + +const MAX_DEG: usize = 5; +const CM_HEIGHT: usize = 10; +const COPY_COL_NUM: usize = 10; + +pub struct TestTable { + pub a: Column, + pub b: Column, +} + +impl LookupTable for TestTable { + fn get_type(&self) -> SingleTable { + SingleTable::Default + } + fn columns(&self) -> Vec> { + vec![self.a.into(), self.b.into()] + } + fn annotations(&self) -> Vec { + vec![String::from("a"), String::from("b")] + } +} + +pub struct TestConfig { + pub(crate) q_count: Column, + pub(crate) cell_columns: Vec>, + pub(crate) cell_gadget: CellGadget, +} + + +impl TestConfig { + pub fn new(meta: &mut ConstraintSystem, table: TestTable) -> Self { + + // Get columns + let q_count = meta.advice_column(); + let cell_columns = (0..10).map(|_| meta.advice_column()).collect::>(); + + // Init cell manager and constraint builder + let phase_config: PhaseConfig = PhaseConfig::new::(vec![&table], 1, 1); + let mut cm = CellManager::new( + meta, + CM_HEIGHT, + &cell_columns, + 0, + phase_config, + COPY_COL_NUM + ); + let mut cb = ConstraintBuilder::new(MAX_DEG, Some(cm)); + + // Init Gadgets + let cell_gadget = CellGadget::configure(&mut cb); + Self { + q_count, + cell_columns, + cell_gadget, + } + } + +} + +#[derive(Clone, Debug, Default)] +pub struct CellGadget { + // a + b == c + // a == d + a: Cell, + b: Cell, + c: Cell, + d: Cell, +} + +impl CellGadget { + pub fn configure(cb: &mut ConstraintBuilder) -> Self { + let a = cb.query_cell(); + let b = cb.query_cell(); + let c = cb.query_cell(); + let d = cb.query_cell(); + circuit!([meta, cb], { + require!((a, b) => @format!("test_lookup")); + require!(c => a.expr() + b.expr()); + require!(a => d.expr()); + }); + CellGadget { a, b, c, d } + } + + pub fn assign(&self, region: &mut CachedRegion<'_, '_, F>, offset: usize) -> Result<(), Error>{ + assign!(region, (self.a.column(), offset) => 2u64.scalar())?; + assign!(region, (self.b.column(), offset) => 3u64.scalar())?; + assign!(region, (self.c.column(), offset) => 5u64.scalar())?; + assign!(region, (self.d.column(), offset) => 2u64.scalar())?; + Ok(()) + } + +} + + + +#[test] +fn test() { + +} \ No newline at end of file From fbbe1bd1a6eacd95daacb6d6b5d15aa2e86d6f8a Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Wed, 10 May 2023 23:11:09 +0800 Subject: [PATCH 033/102] Simplify bytecode circuit assignment (#1397) ### Description We simplify the assignment logic in the bytecode circuit by reducing the number of function arguments. The reduction is achieved by 1. Construct IsZero Chips early and make them a part of the circuit struct so that they don't stay with the function arguments. 2. Create a new row struct that carries all the relevant data. ### Issue Link This would be part of #1391. ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Rationale - I avoid using `BytecodeRow` in the `bytecode_unroller` since they are part of the future simplification plan. ### How Has This Been Tested? Sent to the CI and pray. --- gadgets/src/is_zero.rs | 7 +- .../src/bytecode_circuit/circuit.rs | 226 +++++++----------- 2 files changed, 93 insertions(+), 140 deletions(-) diff --git a/gadgets/src/is_zero.rs b/gadgets/src/is_zero.rs index cc6f3e3a67..a5eb08037c 100644 --- a/gadgets/src/is_zero.rs +++ b/gadgets/src/is_zero.rs @@ -51,11 +51,11 @@ impl IsZeroConfig { } } +#[derive(Debug, Clone)] /// Wrapper arround [`IsZeroConfig`] for which [`Chip`] is implemented. pub struct IsZeroChip { config: IsZeroConfig, } - #[rustfmt::skip] impl IsZeroChip { /// Sets up the configuration of the chip by creating the required columns @@ -105,6 +105,11 @@ impl IsZeroChip { pub fn construct(config: IsZeroConfig) -> Self { IsZeroChip { config } } + + /// Annotates columns of this gadget embedded within a circuit region. + pub fn annotate_columns_in_region(&self, region: &mut Region, prefix: &str) { + self.config.annotate_columns_in_region(region, prefix) + } } impl IsZeroInstruction for IsZeroChip { diff --git a/zkevm-circuits/src/bytecode_circuit/circuit.rs b/zkevm-circuits/src/bytecode_circuit/circuit.rs index cd70f56a42..d0540d3126 100644 --- a/zkevm-circuits/src/bytecode_circuit/circuit.rs +++ b/zkevm-circuits/src/bytecode_circuit/circuit.rs @@ -10,7 +10,7 @@ use crate::{ }; use bus_mapping::state_db::EMPTY_CODE_HASH_LE; use eth_types::{Field, ToLittleEndian}; -use gadgets::is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}; +use gadgets::is_zero::{IsZeroChip, IsZeroInstruction}; use halo2_proofs::{ circuit::{Layouter, Region, Value}, plonk::{ @@ -26,6 +26,43 @@ use super::{ param::PUSH_TABLE_WIDTH, }; +#[derive(Debug, Clone, Default)] +/// Row for assignment +pub struct BytecodeCircuitRow { + offset: usize, + last_row_offset: usize, + code_hash: Value, + tag: F, + index: F, + is_code: F, + value: F, + push_data_left: u64, + value_rlc: Value, + length: F, + push_data_size: F, +} +impl BytecodeCircuitRow { + /// enable selector if we are within the range of table size. + pub fn enable(&self) -> bool { + self.offset <= self.last_row_offset + } + + /// Determine if we are at last row of the bytecode table. + pub fn last(&self) -> bool { + self.offset == self.last_row_offset + } + + /// Get offset + pub fn offset(&self) -> usize { + self.offset + } + + /// Witness to IsZero chip to determine if we are at the last row of a bytecode instance + pub fn diff(&self) -> F { + self.index + F::ONE - self.length + } +} + #[derive(Clone, Debug)] /// Bytecode circuit configuration pub struct BytecodeCircuitConfig { @@ -38,10 +75,8 @@ pub struct BytecodeCircuitConfig { value_rlc: Column, length: Column, push_data_size: Column, - push_data_left_inv: Column, - push_data_left_is_zero: IsZeroConfig, - index_length_diff_inv: Column, - index_length_diff_is_zero: IsZeroConfig, + push_data_left_is_zero: IsZeroChip, + index_length_diff_is_zero: IsZeroChip, push_table: [Column; PUSH_TABLE_WIDTH], // External tables pub(crate) keccak_table: KeccakTable, @@ -141,7 +176,6 @@ impl SubCircuitConfig for BytecodeCircuitConfig { }, index_length_diff_inv, ); - // dbg!(index_length_diff_is_zero.clone().is_zero_expression); // When q_first || q_last -> // assert cur.tag == Header @@ -419,6 +453,9 @@ impl SubCircuitConfig for BytecodeCircuitConfig { }, ); + let push_data_left_is_zero = IsZeroChip::construct(push_data_left_is_zero); + let index_length_diff_is_zero = IsZeroChip::construct(index_length_diff_is_zero); + BytecodeCircuitConfig { minimum_rows: meta.minimum_rows(), q_enable, @@ -429,9 +466,7 @@ impl SubCircuitConfig for BytecodeCircuitConfig { value_rlc, length, push_data_size, - push_data_left_inv, push_data_left_is_zero, - index_length_diff_inv, index_length_diff_is_zero, push_table, keccak_table, @@ -440,17 +475,6 @@ impl SubCircuitConfig for BytecodeCircuitConfig { } impl BytecodeCircuitConfig { - pub(crate) fn assign( - &self, - layouter: &mut impl Layouter, - size: usize, - witness: &[UnrolledBytecode], - overwrite: &UnrolledBytecode, - challenges: &Challenges>, - ) -> Result<(), Error> { - self.assign_internal(layouter, size, witness, overwrite, challenges, true) - } - pub(crate) fn assign_internal( &self, layouter: &mut impl Layouter, @@ -460,11 +484,6 @@ impl BytecodeCircuitConfig { challenges: &Challenges>, fail_fast: bool, ) -> Result<(), Error> { - let push_data_left_is_zero_chip = - IsZeroChip::construct(self.push_data_left_is_zero.clone()); - let index_length_diff_is_zero_chip = - IsZeroChip::construct(self.index_length_diff_is_zero.clone()); - // Subtract the unusable rows from the size assert!(size > self.minimum_rows); let last_row_offset = size - self.minimum_rows + 1; @@ -476,10 +495,6 @@ impl BytecodeCircuitConfig { last_row_offset ); - let empty_hash = challenges - .evm_word() - .map(|challenge| rlc::value(EMPTY_CODE_HASH_LE.as_ref(), challenge)); - layouter.assign_region( || "assign bytecode", |mut region| { @@ -492,9 +507,6 @@ impl BytecodeCircuitConfig { &mut region, bytecode, challenges, - &push_data_left_is_zero_chip, - &index_length_diff_is_zero_chip, - empty_hash, &mut offset, last_row_offset, fail_fast, @@ -503,14 +515,7 @@ impl BytecodeCircuitConfig { // Padding for idx in offset..=last_row_offset { - self.set_padding_row( - &mut region, - &push_data_left_is_zero_chip, - &index_length_diff_is_zero_chip, - empty_hash, - idx, - last_row_offset, - )?; + self.set_padding_row(&mut region, challenges, idx, last_row_offset)?; } // Overwrite the witness assignment by using the values in the `overwrite` @@ -563,15 +568,11 @@ impl BytecodeCircuitConfig { ) } - #[allow(clippy::too_many_arguments)] fn assign_bytecode( &self, region: &mut Region<'_, F>, bytecode: &UnrolledBytecode, challenges: &Challenges>, - push_data_left_is_zero_chip: &IsZeroChip, - index_length_diff_is_zero_chip: &IsZeroChip, - empty_hash: Value, offset: &mut usize, last_row_offset: usize, fail_fast: bool, @@ -620,51 +621,28 @@ impl BytecodeCircuitConfig { // Set the data for this row if *offset < last_row_offset { - self.set_row( - region, - push_data_left_is_zero_chip, - index_length_diff_is_zero_chip, - *offset, - true, - *offset == last_row_offset, + let row = BytecodeCircuitRow { + offset: *offset, + last_row_offset, code_hash, - row.tag, - row.index, - row.is_code, - row.value, + tag: row.tag, + index: row.index, + is_code: row.is_code, + value: row.value, push_data_left, value_rlc, length, - F::from(push_data_size), - )?; + push_data_size: F::from(push_data_size), + }; + self.set_row(region, row.clone())?; - trace!( - "bytecode.set_row({}): last:{} h:{:?} t:{:?} i:{:?} c:{:?} v:{:?} pdl:{} rlc:{:?} l:{:?} pds:{:?}", - offset, - *offset == last_row_offset, - code_hash, - row.tag.get_lower_32(), - row.index.get_lower_32(), - row.is_code.get_lower_32(), - row.value.get_lower_32(), - push_data_left, - value_rlc, - length.get_lower_32(), - push_data_size - ); + trace!("bytecode.set_row({:?})", row); *offset += 1; push_data_left = next_push_data_left } if *offset == last_row_offset { - self.set_padding_row( - region, - push_data_left_is_zero_chip, - index_length_diff_is_zero_chip, - empty_hash, - *offset, - last_row_offset, - )?; + self.set_padding_row(region, challenges, *offset, last_row_offset)?; } } @@ -674,56 +652,35 @@ impl BytecodeCircuitConfig { fn set_padding_row( &self, region: &mut Region<'_, F>, - push_data_left_is_zero_chip: &IsZeroChip, - index_length_diff_is_zero_chip: &IsZeroChip, - empty_hash: Value, + challenges: &Challenges>, offset: usize, last_row_offset: usize, ) -> Result<(), Error> { + let empty_hash = challenges + .evm_word() + .map(|challenge| rlc::value(EMPTY_CODE_HASH_LE.as_ref(), challenge)); + self.set_row( region, - push_data_left_is_zero_chip, - index_length_diff_is_zero_chip, - offset, - offset <= last_row_offset, - offset == last_row_offset, - empty_hash, - F::from(BytecodeFieldTag::Header as u64), - F::ZERO, - F::ZERO, - F::ZERO, - 0, - Value::known(F::ZERO), - F::ZERO, - F::ZERO, + BytecodeCircuitRow { + offset, + last_row_offset, + code_hash: empty_hash, + tag: F::from(BytecodeFieldTag::Header as u64), + value_rlc: Value::known(F::ZERO), + ..Default::default() + }, ) } - #[allow(clippy::too_many_arguments)] - fn set_row( - &self, - region: &mut Region<'_, F>, - push_data_left_is_zero_chip: &IsZeroChip, - index_length_diff_is_zero_chip: &IsZeroChip, - offset: usize, - enable: bool, - last: bool, - code_hash: Value, - tag: F, - index: F, - is_code: F, - value: F, - push_data_left: u64, - value_rlc: Value, - length: F, - push_data_size: F, - ) -> Result<(), Error> { + fn set_row(&self, region: &mut Region<'_, F>, row: BytecodeCircuitRow) -> Result<(), Error> { + let offset = row.offset; // q_enable region.assign_fixed( || format!("assign q_enable {}", offset), self.q_enable, offset, - || Value::known(F::from(enable as u64)), + || Value::known(F::from(row.enable().into())), )?; // q_first @@ -731,31 +688,30 @@ impl BytecodeCircuitConfig { || format!("assign q_first {}", offset), self.q_first, offset, - || Value::known(F::from((offset == 0) as u64)), + || Value::known(F::from((offset == 0).into())), )?; // q_last - let q_last_value = if last { F::ONE } else { F::ZERO }; region.assign_fixed( || format!("assign q_last {}", offset), self.q_last, offset, - || Value::known(q_last_value), + || Value::known(F::from(row.last().into())), )?; // Advices for (name, column, value) in [ - ("tag", self.bytecode_table.tag, tag), - ("index", self.bytecode_table.index, index), - ("is_code", self.bytecode_table.is_code, is_code), - ("value", self.bytecode_table.value, value), + ("tag", self.bytecode_table.tag, row.tag), + ("index", self.bytecode_table.index, row.index), + ("is_code", self.bytecode_table.is_code, row.is_code), + ("value", self.bytecode_table.value, row.value), ( "push_data_left", self.push_data_left, - F::from(push_data_left), + F::from(row.push_data_left), ), - ("length", self.length, length), - ("push_data_size", self.push_data_size, push_data_size), + ("length", self.length, row.length), + ("push_data_size", self.push_data_size, row.push_data_size), ] { region.assign_advice( || format!("assign {} {}", name, offset), @@ -765,8 +721,8 @@ impl BytecodeCircuitConfig { )?; } for (name, column, value) in [ - ("code_hash", self.bytecode_table.code_hash, code_hash), - ("value_rlc", self.value_rlc, value_rlc), + ("code_hash", self.bytecode_table.code_hash, row.code_hash), + ("value_rlc", self.value_rlc, row.value_rlc), ] { region.assign_advice( || format!("assign {} {}", name, offset), @@ -776,17 +732,14 @@ impl BytecodeCircuitConfig { )?; } - push_data_left_is_zero_chip.assign( + self.push_data_left_is_zero.assign( region, offset, - Value::known(F::from(push_data_left)), + Value::known(F::from(row.push_data_left)), )?; - index_length_diff_is_zero_chip.assign( - region, - offset, - Value::known(index + F::ONE - length), - )?; + self.index_length_diff_is_zero + .assign(region, offset, Value::known(row.diff()))?; Ok(()) } @@ -806,11 +759,6 @@ impl BytecodeCircuitConfig { region.name_column(|| "BYTECODE_push_data_left", self.push_data_left); region.name_column(|| "BYTECODE_push_data_size", self.push_data_size); region.name_column(|| "BYTECODE_value_rlc", self.value_rlc); - region.name_column(|| "BYTECODE_push_data_left_inv", self.push_data_left_inv); - region.name_column( - || "BYTECODE_index_length_diff_inv", - self.index_length_diff_inv, - ); } /// load fixed tables From a807754c0c094261551f3d2dabff2857b34466f2 Mon Sep 17 00:00:00 2001 From: "adria0.eth" <5526331+adria0@users.noreply.github.com> Date: Wed, 10 May 2023 18:04:57 +0200 Subject: [PATCH 034/102] fix(testool): fix coinbase, solves #1160 (#1400) ### Description When running `testool --oneliner`, set the coinbase to `MOCK_COINBASE` and top up with 1 wei to register it into the state db. ### Issue Link #1160 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update Co-authored-by: adria0 --- testool/src/statetest/spec.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/testool/src/statetest/spec.rs b/testool/src/statetest/spec.rs index b2d224a73f..12b06baa14 100644 --- a/testool/src/statetest/spec.rs +++ b/testool/src/statetest/spec.rs @@ -250,11 +250,20 @@ impl StateTest { ); } + pre.insert( + *mock::MOCK_COINBASE, + Account { + address: *mock::MOCK_COINBASE, + balance: U256::from(1), + ..Default::default() + }, + ); + let state_test = StateTest { path: String::default(), id: String::default(), env: Env { - current_coinbase: Address::default(), + current_coinbase: *mock::MOCK_COINBASE, current_difficulty: U256::default(), current_gas_limit: 16000000, current_number: 1, From 14bd7c9ca95a5b0ed50d78750414e8c11f799e8e Mon Sep 17 00:00:00 2001 From: Eduard S Date: Thu, 11 May 2023 10:18:05 +0200 Subject: [PATCH 035/102] Use halo2 circuit-params feature (#1399) Refactor SuperCircuit and PiCircuit to use circuit parameters instead of associated constants. Resolve https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1393 ### Type of change - [x] Breaking change (fix or feature that would cause existing functionality to not work as expected) ### Contents Using the `circuit-params` feature recently introduced in our fork of halo2 allows simplifying the code for circuits that require runtime parameters at configuration time. It removes the annoying associated const of the circuit types, and also allows having a single circuit type (no need for an extra circuit test type). --- circuit-benchmarks/src/pi_circuit.rs | 21 ++--- circuit-benchmarks/src/super_circuit.rs | 10 +-- gadgets/src/batched_is_zero.rs | 1 + gadgets/src/evm_word.rs | 1 + gadgets/src/is_zero.rs | 2 + gadgets/src/less_than.rs | 2 + gadgets/src/monotone.rs | 1 + gadgets/src/mul_add.rs | 1 + .../src/integration_test_circuits.rs | 2 +- testool/src/statetest/executor.rs | 10 +-- zkevm-circuits/Cargo.toml | 2 +- zkevm-circuits/src/bytecode_circuit/dev.rs | 1 + zkevm-circuits/src/bytecode_circuit/test.rs | 2 +- zkevm-circuits/src/copy_circuit/dev.rs | 1 + zkevm-circuits/src/copy_circuit/test.rs | 2 +- zkevm-circuits/src/evm_circuit.rs | 4 +- .../evm_circuit/util/math_gadget/test_util.rs | 1 + zkevm-circuits/src/exp_circuit/dev.rs | 1 + zkevm-circuits/src/exp_circuit/test.rs | 2 +- zkevm-circuits/src/keccak_circuit/dev.rs | 1 + zkevm-circuits/src/keccak_circuit/table.rs | 1 + zkevm-circuits/src/keccak_circuit/test.rs | 2 +- zkevm-circuits/src/pi_circuit.rs | 2 - zkevm-circuits/src/pi_circuit/dev.rs | 79 ++++++------------ zkevm-circuits/src/pi_circuit/test.rs | 63 +++++++------- zkevm-circuits/src/root_circuit.rs | 1 + .../src/root_circuit/aggregation.rs | 2 + zkevm-circuits/src/root_circuit/test.rs | 13 +-- zkevm-circuits/src/state_circuit/dev.rs | 1 + zkevm-circuits/src/state_circuit/test.rs | 2 +- zkevm-circuits/src/super_circuit.rs | 83 +++++++++++-------- zkevm-circuits/src/super_circuit/test.rs | 43 ++++------ zkevm-circuits/src/tx_circuit/dev.rs | 1 + zkevm-circuits/src/tx_circuit/sign_verify.rs | 1 + zkevm-circuits/src/tx_circuit/test.rs | 2 +- zkevm-circuits/src/util.rs | 4 +- zkevm-circuits/tests/prover_error.rs | 13 ++- 37 files changed, 174 insertions(+), 207 deletions(-) diff --git a/circuit-benchmarks/src/pi_circuit.rs b/circuit-benchmarks/src/pi_circuit.rs index 3f0b150882..eb1295e129 100644 --- a/circuit-benchmarks/src/pi_circuit.rs +++ b/circuit-benchmarks/src/pi_circuit.rs @@ -24,7 +24,7 @@ mod tests { use rand_xorshift::XorShiftRng; use std::env::var; use zkevm_circuits::{ - pi_circuit::{PiCircuit, PiTestCircuit, PublicData}, + pi_circuit::{PiCircuit, PublicData}, util::SubCircuit, }; @@ -48,15 +48,10 @@ mod tests { let mut rng = ChaCha20Rng::seed_from_u64(2); let randomness = Fr::random(&mut rng); let rand_rpi = Fr::random(&mut rng); - let public_data = generate_publicdata::(); - let circuit = PiTestCircuit::(PiCircuit::::new( - MAX_TXS, - MAX_CALLDATA, - randomness, - rand_rpi, - public_data, - )); - let public_inputs = circuit.0.instance(); + let public_data = generate_publicdata(MAX_TXS); + let circuit = + PiCircuit::::new(MAX_TXS, MAX_CALLDATA, randomness, rand_rpi, public_data); + let public_inputs = circuit.instance(); let instance: Vec<&[Fr]> = public_inputs.iter().map(|input| &input[..]).collect(); let instances = &[&instance[..]]; @@ -90,7 +85,7 @@ mod tests { Challenge255, XorShiftRng, Blake2bWrite, G1Affine, Challenge255>, - PiTestCircuit, + PiCircuit, >( &general_params, &pk, @@ -125,12 +120,12 @@ mod tests { end_timer!(start3); } - fn generate_publicdata() -> PublicData { + fn generate_publicdata(max_txs: usize) -> PublicData { let mut public_data = PublicData::default(); let chain_id = 1337u64; public_data.chain_id = Word::from(chain_id); - let n_tx = MAX_TXS; + let n_tx = max_txs; for _ in 0..n_tx { let eth_tx = eth_types::Transaction::from(mock::CORRECT_MOCK_TXS[0].clone()); public_data.transactions.push(eth_tx); diff --git a/circuit-benchmarks/src/super_circuit.rs b/circuit-benchmarks/src/super_circuit.rs index bac05c75e1..a37ffa82d8 100644 --- a/circuit-benchmarks/src/super_circuit.rs +++ b/circuit-benchmarks/src/super_circuit.rs @@ -79,11 +79,9 @@ mod tests { block.sign(&wallets); - const MAX_TXS: usize = 1; - const MAX_CALLDATA: usize = 32; let circuits_params = CircuitsParams { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, + max_txs: 1, + max_calldata: 32, max_rws: 256, max_copy_rows: 256, max_exp_steps: 256, @@ -92,7 +90,7 @@ mod tests { max_keccak_rows: 0, }; let (_, circuit, instance, _) = - SuperCircuit::<_, MAX_TXS, MAX_CALLDATA, 0x100>::build(block, circuits_params).unwrap(); + SuperCircuit::build(block, circuits_params, Fr::from(0x100)).unwrap(); let instance_refs: Vec<&[Fr]> = instance.iter().map(|v| &v[..]).collect(); // Bench setup generation @@ -120,7 +118,7 @@ mod tests { Challenge255, ChaChaRng, Blake2bWrite, G1Affine, Challenge255>, - SuperCircuit, + SuperCircuit, >( &general_params, &pk, diff --git a/gadgets/src/batched_is_zero.rs b/gadgets/src/batched_is_zero.rs index 2f3acb2c22..6f4ff461a9 100644 --- a/gadgets/src/batched_is_zero.rs +++ b/gadgets/src/batched_is_zero.rs @@ -158,6 +158,7 @@ mod test { impl Circuit for TestCircuit { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/gadgets/src/evm_word.rs b/gadgets/src/evm_word.rs index 16f85c70e3..3245bd327f 100644 --- a/gadgets/src/evm_word.rs +++ b/gadgets/src/evm_word.rs @@ -178,6 +178,7 @@ mod tests { // commitment which will be provided as public inputs. type Config = (WordConfig, Column); type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/gadgets/src/is_zero.rs b/gadgets/src/is_zero.rs index a5eb08037c..be552b1f89 100644 --- a/gadgets/src/is_zero.rs +++ b/gadgets/src/is_zero.rs @@ -213,6 +213,7 @@ mod test { impl Circuit for TestCircuit { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() @@ -340,6 +341,7 @@ mod test { impl Circuit for TestCircuit { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/gadgets/src/less_than.rs b/gadgets/src/less_than.rs index db539af086..49285951da 100644 --- a/gadgets/src/less_than.rs +++ b/gadgets/src/less_than.rs @@ -243,6 +243,7 @@ mod test { impl Circuit for TestCircuit { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() @@ -363,6 +364,7 @@ mod test { impl Circuit for TestCircuit { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/gadgets/src/monotone.rs b/gadgets/src/monotone.rs index 39d4b6cf64..3d37a4366f 100644 --- a/gadgets/src/monotone.rs +++ b/gadgets/src/monotone.rs @@ -137,6 +137,7 @@ mod test { { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/gadgets/src/mul_add.rs b/gadgets/src/mul_add.rs index 5433b8dd80..3710f7b9c6 100644 --- a/gadgets/src/mul_add.rs +++ b/gadgets/src/mul_add.rs @@ -443,6 +443,7 @@ mod test { impl Circuit for TestCircuit { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn configure(meta: &mut halo2_proofs::plonk::ConstraintSystem) -> Self::Config { let q_enable = meta.complex_selector(); diff --git a/integration-tests/src/integration_test_circuits.rs b/integration-tests/src/integration_test_circuits.rs index 5eb08aa43a..4987bbfadd 100644 --- a/integration-tests/src/integration_test_circuits.rs +++ b/integration-tests/src/integration_test_circuits.rs @@ -119,7 +119,7 @@ lazy_static! { TokioMutex::new(IntegrationTest::new("Keccak", KECCAK_CIRCUIT_DEGREE)); /// Integration test for Copy circuit - pub static ref SUPER_CIRCUIT_TEST: TokioMutex>> = + pub static ref SUPER_CIRCUIT_TEST: TokioMutex>> = TokioMutex::new(IntegrationTest::new("Super", SUPER_CIRCUIT_DEGREE)); /// Integration test for Exp circuit diff --git a/testool/src/statetest/executor.rs b/testool/src/statetest/executor.rs index 7a978934dc..16cd0927f1 100644 --- a/testool/src/statetest/executor.rs +++ b/testool/src/statetest/executor.rs @@ -16,9 +16,6 @@ use std::{collections::HashMap, str::FromStr}; use thiserror::Error; use zkevm_circuits::{super_circuit::SuperCircuit, test_util::CircuitTestBuilder, witness::Block}; -const MAX_TXS: usize = 1; -const MAX_CALLDATA: usize = 32; - #[derive(PartialEq, Eq, Error, Debug)] pub enum StateTestError { #[error("CannotGenerateCircuitInput({0})")] @@ -277,8 +274,8 @@ pub fn run_test( geth_data.sign(&wallets); let circuits_params = CircuitsParams { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, + max_txs: 1, + max_calldata: 32, max_rws: 256, max_copy_rows: 256, max_exp_steps: 256, @@ -287,8 +284,7 @@ pub fn run_test( max_keccak_rows: 0, }; let (k, circuit, instance, _builder) = - SuperCircuit::::build(geth_data, circuits_params) - .unwrap(); + SuperCircuit::::build(geth_data, circuits_params, Fr::from(0x100)).unwrap(); builder = _builder; let prover = MockProver::run(k, &circuit, instance).unwrap(); diff --git a/zkevm-circuits/Cargo.toml b/zkevm-circuits/Cargo.toml index 846dbc73c9..433f1a99b5 100644 --- a/zkevm-circuits/Cargo.toml +++ b/zkevm-circuits/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", features = ["circuit-params"], tag = "v2023_04_20" } num = "0.4" sha3 = "0.10" array-init = "2.0.0" diff --git a/zkevm-circuits/src/bytecode_circuit/dev.rs b/zkevm-circuits/src/bytecode_circuit/dev.rs index dd33c563ab..178aecc90d 100644 --- a/zkevm-circuits/src/bytecode_circuit/dev.rs +++ b/zkevm-circuits/src/bytecode_circuit/dev.rs @@ -14,6 +14,7 @@ use halo2_proofs::{ impl Circuit for BytecodeCircuit { type Config = (BytecodeCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/zkevm-circuits/src/bytecode_circuit/test.rs b/zkevm-circuits/src/bytecode_circuit/test.rs index 8ebed96b0b..c765aec905 100644 --- a/zkevm-circuits/src/bytecode_circuit/test.rs +++ b/zkevm-circuits/src/bytecode_circuit/test.rs @@ -13,7 +13,7 @@ use log::error; fn bytecode_circuit_unusable_rows() { assert_eq!( BytecodeCircuit::::unusable_rows(), - unusable_rows::>(), + unusable_rows::>(()), ) } diff --git a/zkevm-circuits/src/copy_circuit/dev.rs b/zkevm-circuits/src/copy_circuit/dev.rs index 9671989777..996b12b07a 100644 --- a/zkevm-circuits/src/copy_circuit/dev.rs +++ b/zkevm-circuits/src/copy_circuit/dev.rs @@ -14,6 +14,7 @@ use halo2_proofs::{ impl Circuit for CopyCircuit { type Config = (CopyCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/zkevm-circuits/src/copy_circuit/test.rs b/zkevm-circuits/src/copy_circuit/test.rs index 81d0183ee3..88fdd3e170 100644 --- a/zkevm-circuits/src/copy_circuit/test.rs +++ b/zkevm-circuits/src/copy_circuit/test.rs @@ -22,7 +22,7 @@ use mock::{test_ctx::helpers::account_0_code_account_1_no_code, TestContext, MOC fn copy_circuit_unusable_rows() { assert_eq!( CopyCircuit::::unusable_rows(), - unusable_rows::>(), + unusable_rows::>(()), ) } diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index e1f19121ed..be8257f021 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -329,6 +329,7 @@ pub(crate) mod cached { impl Circuit for EvmCircuitCached { type Config = (EvmCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self(self.0.without_witnesses()) @@ -359,6 +360,7 @@ pub(crate) mod cached { impl Circuit for EvmCircuit { type Config = (EvmCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() @@ -470,7 +472,7 @@ mod evm_circuit_stats { fn evm_circuit_unusable_rows() { assert_eq!( EvmCircuit::::unusable_rows(), - unusable_rows::>(), + unusable_rows::>(()), ) } diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs index 823cf99bd4..0541bc0fc1 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs @@ -90,6 +90,7 @@ impl UnitTestMathGadgetBaseCircuit { impl> Circuit for UnitTestMathGadgetBaseCircuit { type Config = (UnitTestMathGadgetBaseCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { UnitTestMathGadgetBaseCircuit { diff --git a/zkevm-circuits/src/exp_circuit/dev.rs b/zkevm-circuits/src/exp_circuit/dev.rs index 45a1831b6d..ebb5cb4d31 100644 --- a/zkevm-circuits/src/exp_circuit/dev.rs +++ b/zkevm-circuits/src/exp_circuit/dev.rs @@ -14,6 +14,7 @@ use halo2_proofs::{ impl Circuit for ExpCircuit { type Config = (ExpCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/zkevm-circuits/src/exp_circuit/test.rs b/zkevm-circuits/src/exp_circuit/test.rs index 2df199f217..2b5012458d 100644 --- a/zkevm-circuits/src/exp_circuit/test.rs +++ b/zkevm-circuits/src/exp_circuit/test.rs @@ -19,7 +19,7 @@ use mock::TestContext; fn exp_circuit_unusable_rows() { assert_eq!( ExpCircuit::::unusable_rows(), - unusable_rows::>(), + unusable_rows::>(()), ) } diff --git a/zkevm-circuits/src/keccak_circuit/dev.rs b/zkevm-circuits/src/keccak_circuit/dev.rs index 44e7ac07a5..12709bc41e 100644 --- a/zkevm-circuits/src/keccak_circuit/dev.rs +++ b/zkevm-circuits/src/keccak_circuit/dev.rs @@ -14,6 +14,7 @@ use halo2_proofs::{ impl Circuit for KeccakCircuit { type Config = (KeccakCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/zkevm-circuits/src/keccak_circuit/table.rs b/zkevm-circuits/src/keccak_circuit/table.rs index 74c5959f51..5ab2fc5e23 100644 --- a/zkevm-circuits/src/keccak_circuit/table.rs +++ b/zkevm-circuits/src/keccak_circuit/table.rs @@ -246,6 +246,7 @@ mod tests { impl Circuit for TableTestCircuit { type Config = [TableColumn; 2]; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { self.clone() diff --git a/zkevm-circuits/src/keccak_circuit/test.rs b/zkevm-circuits/src/keccak_circuit/test.rs index 939dad046d..9711f978d5 100644 --- a/zkevm-circuits/src/keccak_circuit/test.rs +++ b/zkevm-circuits/src/keccak_circuit/test.rs @@ -22,7 +22,7 @@ fn serial_keccak_circuit_unusable_rows() { std::env::set_var("KECCAK_ROWS", format!("{keccak_rows}")); assert_eq!( KeccakCircuit::::unusable_rows(), - unusable_rows::>(), + unusable_rows::>(()), ) } std::env::set_var("KECCAK_ROWS", format!("{DEFAULT_KECCAK_ROWS}")); diff --git a/zkevm-circuits/src/pi_circuit.rs b/zkevm-circuits/src/pi_circuit.rs index a5ff18a185..d5b4523ebd 100644 --- a/zkevm-circuits/src/pi_circuit.rs +++ b/zkevm-circuits/src/pi_circuit.rs @@ -5,8 +5,6 @@ mod param; mod dev; #[cfg(any(feature = "test", test))] mod test; -#[cfg(any(feature = "test", test, feature = "test-circuits"))] -pub use dev::PiTestCircuit; use eth_types::{ geth_types::{BlockConstants, Transaction}, diff --git a/zkevm-circuits/src/pi_circuit/dev.rs b/zkevm-circuits/src/pi_circuit/dev.rs index 1af92653ee..1718853b18 100644 --- a/zkevm-circuits/src/pi_circuit/dev.rs +++ b/zkevm-circuits/src/pi_circuit/dev.rs @@ -1,74 +1,39 @@ use super::*; -// We define the PiTestCircuit as a wrapper over PiCircuit extended to take the -// generic const parameters MAX_TXS and MAX_CALLDATA. This is necessary because -// the trait Circuit requires an implementation of `configure` that doesn't take -// any circuit parameters, and the PiCircuit defines gates that use rotations -// that depend on MAX_TXS and MAX_CALLDATA, so these two values are required -// during the configuration. -/// Test Circuit for PiCircuit -#[derive(Default, Clone)] -pub struct PiTestCircuit( - pub PiCircuit, -); - -impl SubCircuit - for PiTestCircuit -{ - type Config = PiCircuitConfig; - - fn unusable_rows() -> usize { - PiCircuit::::unusable_rows() - } - - fn new_from_block(block: &witness::Block) -> Self { - assert_eq!(block.circuits_params.max_txs, MAX_TXS); - assert_eq!(block.circuits_params.max_calldata, MAX_CALLDATA); - - Self(PiCircuit::new_from_block(block)) - } - - fn min_num_rows_block(block: &witness::Block) -> (usize, usize) { - assert_eq!(block.circuits_params.max_txs, MAX_TXS); - assert_eq!(block.circuits_params.max_calldata, MAX_CALLDATA); - - PiCircuit::min_num_rows_block(block) - } - - /// Compute the public inputs for this circuit. - fn instance(&self) -> Vec> { - self.0.instance() - } - - fn synthesize_sub( - &self, - _config: &Self::Config, - _challenges: &Challenges>, - _layouter: &mut impl Layouter, - ) -> Result<(), Error> { - panic!("use PiCircuit for embedding instead"); - } +/// Public Input Circuit configuration parameters +#[derive(Default)] +pub struct PiCircuitParams { + /// Max Txs + pub max_txs: usize, + /// Max Calldata + pub max_calldata: usize, } -impl Circuit - for PiTestCircuit -{ +impl Circuit for PiCircuit { type Config = (PiCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; + type Params = PiCircuitParams; fn without_witnesses(&self) -> Self { Self::default() } - fn configure(meta: &mut ConstraintSystem) -> Self::Config { + fn params(&self) -> Self::Params { + PiCircuitParams { + max_txs: self.max_txs, + max_calldata: self.max_calldata, + } + } + + fn configure_with_params(meta: &mut ConstraintSystem, params: Self::Params) -> Self::Config { let block_table = BlockTable::construct(meta); let tx_table = TxTable::construct(meta); ( PiCircuitConfig::new( meta, PiCircuitConfigArgs { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, + max_txs: params.max_txs, + max_calldata: params.max_calldata, block_table, tx_table, }, @@ -77,12 +42,16 @@ impl Circuit ) } + fn configure(_meta: &mut ConstraintSystem) -> Self::Config { + unreachable!(); + } + fn synthesize( &self, (config, challenges): Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { let challenges = challenges.values(&mut layouter); - self.0.synthesize_sub(&config, &challenges, &mut layouter) + self.synthesize_sub(&config, &challenges, &mut layouter) } } diff --git a/zkevm-circuits/src/pi_circuit/test.rs b/zkevm-circuits/src/pi_circuit/test.rs index ddd453e110..5b6db6499b 100644 --- a/zkevm-circuits/src/pi_circuit/test.rs +++ b/zkevm-circuits/src/pi_circuit/test.rs @@ -11,16 +11,19 @@ use rand_chacha::ChaCha20Rng; #[test] fn pi_circuit_unusable_rows() { - const MAX_TXS: usize = 2; - const MAX_CALLDATA: usize = 8; assert_eq!( PiCircuit::::unusable_rows(), - unusable_rows::>(), + unusable_rows::>(PiCircuitParams { + max_txs: 2, + max_calldata: 8, + }), ) } -fn run( +fn run( k: u32, + max_txs: usize, + max_calldata: usize, public_data: PublicData, ) -> Result<(), Vec> { let mut rng = ChaCha20Rng::seed_from_u64(2); @@ -29,14 +32,8 @@ fn run( let mut public_data = public_data; public_data.chain_id = *MOCK_CHAIN_ID; - let circuit = PiTestCircuit::(PiCircuit::new( - MAX_TXS, - MAX_CALLDATA, - randomness, - rand_rpi, - public_data, - )); - let public_inputs = circuit.0.instance(); + let circuit = PiCircuit::::new(max_txs, max_calldata, randomness, rand_rpi, public_data); + let public_inputs = circuit.instance(); let prover = match MockProver::run(k, &circuit, public_inputs) { Ok(prover) => prover, @@ -47,18 +44,18 @@ fn run( #[test] fn test_default_pi() { - const MAX_TXS: usize = 2; - const MAX_CALLDATA: usize = 8; + let max_txs = 2; + let max_calldata = 8; let public_data = PublicData::default(); let k = 17; - assert_eq!(run::(k, public_data), Ok(())); + assert_eq!(run::(k, max_txs, max_calldata, public_data), Ok(())); } #[test] fn test_simple_pi() { - const MAX_TXS: usize = 8; - const MAX_CALLDATA: usize = 200; + let max_txs = 8; + let max_calldata = 200; let mut public_data = PublicData::default(); @@ -70,34 +67,32 @@ fn test_simple_pi() { } let k = 17; - assert_eq!(run::(k, public_data), Ok(())); + assert_eq!(run::(k, max_txs, max_calldata, public_data), Ok(())); } -fn run_size_check( - public_data: [PublicData; 2], -) { +fn run_size_check(max_txs: usize, max_calldata: usize, public_data: [PublicData; 2]) { let mut rng = ChaCha20Rng::seed_from_u64(2); let randomness = F::random(&mut rng); let rand_rpi = F::random(&mut rng); - let circuit = PiTestCircuit::(PiCircuit::new( - MAX_TXS, - MAX_CALLDATA, + let circuit = PiCircuit::::new( + max_txs, + max_calldata, randomness, rand_rpi, public_data[0].clone(), - )); - let public_inputs = circuit.0.instance(); + ); + let public_inputs = circuit.instance(); let prover1 = MockProver::run(20, &circuit, public_inputs).unwrap(); - let circuit2 = PiTestCircuit::(PiCircuit::new( - MAX_TXS, - MAX_CALLDATA, + let circuit2 = PiCircuit::new( + max_txs, + max_calldata, randomness, rand_rpi, public_data[1].clone(), - )); - let public_inputs = circuit2.0.instance(); + ); + let public_inputs = circuit2.instance(); let prover2 = MockProver::run(20, &circuit, public_inputs).unwrap(); assert_eq!(prover1.fixed(), prover2.fixed()); @@ -106,8 +101,8 @@ fn run_size_check( #[test] fn variadic_size_check() { - const MAX_TXS: usize = 8; - const MAX_CALLDATA: usize = 200; + let max_txs = 8; + let max_calldata = 200; let mut pub_dat_1 = PublicData { chain_id: *MOCK_CHAIN_ID, @@ -133,5 +128,5 @@ fn variadic_size_check() { .push(CORRECT_MOCK_TXS[i].clone().into()); } - run_size_check::([pub_dat_1, pub_dat_2]); + run_size_check::(max_txs, max_calldata, [pub_dat_1, pub_dat_2]); } diff --git a/zkevm-circuits/src/root_circuit.rs b/zkevm-circuits/src/root_circuit.rs index 4a45a62e1a..d990f68b65 100644 --- a/zkevm-circuits/src/root_circuit.rs +++ b/zkevm-circuits/src/root_circuit.rs @@ -110,6 +110,7 @@ where { type Config = AggregationConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self { diff --git a/zkevm-circuits/src/root_circuit/aggregation.rs b/zkevm-circuits/src/root_circuit/aggregation.rs index db3a2127fe..5e51ad5d9f 100644 --- a/zkevm-circuits/src/root_circuit/aggregation.rs +++ b/zkevm-circuits/src/root_circuit/aggregation.rs @@ -446,6 +446,7 @@ where { type Config = AggregationConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self { @@ -609,6 +610,7 @@ pub mod test { impl Circuit for StandardPlonk { type Config = StandardPlonkConfig; type FloorPlanner = V1; + type Params = (); fn without_witnesses(&self) -> Self { *self diff --git a/zkevm-circuits/src/root_circuit/test.rs b/zkevm-circuits/src/root_circuit/test.rs index 36106bc899..0f372fe629 100644 --- a/zkevm-circuits/src/root_circuit/test.rs +++ b/zkevm-circuits/src/root_circuit/test.rs @@ -20,12 +20,10 @@ use rand::rngs::OsRng; fn test_root_circuit() { let (params, protocol, proof, instance) = { // Preprocess - const MAX_TXS: usize = 1; - const MAX_CALLDATA: usize = 32; const TEST_MOCK_RANDOMNESS: u64 = 0x100; let circuits_params = CircuitsParams { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, + max_txs: 1, + max_calldata: 32, max_rws: 256, max_copy_rows: 256, max_exp_steps: 256, @@ -34,11 +32,8 @@ fn test_root_circuit() { max_keccak_rows: 0, }; let (k, circuit, instance, _) = - SuperCircuit::<_, MAX_TXS, MAX_CALLDATA, TEST_MOCK_RANDOMNESS>::build( - block_1tx(), - circuits_params, - ) - .unwrap(); + SuperCircuit::<_>::build(block_1tx(), circuits_params, TEST_MOCK_RANDOMNESS.into()) + .unwrap(); let params = ParamsKZG::::setup(k, OsRng); let pk = keygen_pk(¶ms, keygen_vk(¶ms, &circuit).unwrap(), &circuit).unwrap(); let protocol = compile( diff --git a/zkevm-circuits/src/state_circuit/dev.rs b/zkevm-circuits/src/state_circuit/dev.rs index db8262fcce..83769a9057 100644 --- a/zkevm-circuits/src/state_circuit/dev.rs +++ b/zkevm-circuits/src/state_circuit/dev.rs @@ -17,6 +17,7 @@ where { type Config = (StateCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/zkevm-circuits/src/state_circuit/test.rs b/zkevm-circuits/src/state_circuit/test.rs index b8eb3841dc..bd3c1afd9f 100644 --- a/zkevm-circuits/src/state_circuit/test.rs +++ b/zkevm-circuits/src/state_circuit/test.rs @@ -32,7 +32,7 @@ const N_ROWS: usize = 1 << 16; fn state_circuit_unusable_rows() { assert_eq!( StateCircuit::::unusable_rows(), - unusable_rows::>(), + unusable_rows::>(()), ) } diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index f203e5d3cc..cb5deac7f7 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -98,17 +98,17 @@ pub struct SuperCircuitConfig { } /// Circuit configuration arguments -pub struct SuperCircuitConfigArgs { +pub struct SuperCircuitConfigArgs { /// Max txs pub max_txs: usize, /// Max calldata pub max_calldata: usize, /// Mock randomness - pub mock_randomness: u64, + pub mock_randomness: F, } impl SubCircuitConfig for SuperCircuitConfig { - type ConfigArgs = SuperCircuitConfigArgs; + type ConfigArgs = SuperCircuitConfigArgs; /// Configure SuperCircuitConfig fn new( @@ -131,9 +131,8 @@ impl SubCircuitConfig for SuperCircuitConfig { // Use a mock randomness instead of the randomness derived from the challange // (either from mock or real prover) to help debugging assignments. - let power_of_randomness: [Expression; 31] = array::from_fn(|i| { - Expression::Constant(F::from(mock_randomness).pow([1 + i as u64, 0, 0, 0])) - }); + let power_of_randomness: [Expression; 31] = + array::from_fn(|i| Expression::Constant(mock_randomness.pow([1 + i as u64, 0, 0, 0]))); let challenges = Challenges::mock( power_of_randomness[0].clone(), @@ -225,12 +224,7 @@ impl SubCircuitConfig for SuperCircuitConfig { /// The Super Circuit contains all the zkEVM circuits #[derive(Clone, Default, Debug)] -pub struct SuperCircuit< - F: Field, - const MAX_TXS: usize, - const MAX_CALLDATA: usize, - const MOCK_RANDOMNESS: u64, -> { +pub struct SuperCircuit { /// EVM Circuit pub evm_circuit: EvmCircuit, /// State Circuit @@ -247,15 +241,16 @@ pub struct SuperCircuit< pub exp_circuit: ExpCircuit, /// Keccak Circuit pub keccak_circuit: KeccakCircuit, + /// Circuits Parameters + pub circuits_params: CircuitsParams, + /// Mock randomness + pub mock_randomness: F, } -impl - SuperCircuit -{ +impl SuperCircuit { /// Return the number of rows required to verify a given block pub fn get_num_rows_required(block: &Block) -> usize { let num_rows_evm_circuit = EvmCircuit::::get_num_rows_required(block); - assert_eq!(block.circuits_params.max_txs, MAX_TXS); let num_rows_tx_circuit = TxCircuitConfig::::get_num_rows_required(block.circuits_params.max_txs); num_rows_evm_circuit.max(num_rows_tx_circuit) @@ -265,9 +260,7 @@ impl - SubCircuit for SuperCircuit -{ +impl SubCircuit for SuperCircuit { type Config = SuperCircuitConfig; fn unusable_rows() -> usize { @@ -294,7 +287,7 @@ impl { + SuperCircuit::<_> { evm_circuit, state_circuit, tx_circuit, @@ -303,6 +296,8 @@ impl - Circuit for SuperCircuit -{ +/// Super Circuit configuration parameters +#[derive(Default)] +pub struct SuperCircuitParams { + max_txs: usize, + max_calldata: usize, + mock_randomness: F, +} + +impl Circuit for SuperCircuit { type Config = SuperCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = SuperCircuitParams; fn without_witnesses(&self) -> Self { Self::default() } - fn configure(meta: &mut ConstraintSystem) -> Self::Config { + fn params(&self) -> Self::Params { + SuperCircuitParams { + max_txs: self.circuits_params.max_txs, + max_calldata: self.circuits_params.max_calldata, + mock_randomness: self.mock_randomness, + } + } + + fn configure_with_params(meta: &mut ConstraintSystem, params: Self::Params) -> Self::Config { Self::Config::new( meta, SuperCircuitConfigArgs { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, - mock_randomness: MOCK_RANDOMNESS, + max_txs: params.max_txs, + max_calldata: params.max_calldata, + mock_randomness: params.mock_randomness, }, ) } + fn configure(_meta: &mut ConstraintSystem) -> Self::Config { + unreachable!(); + } + fn synthesize( &self, config: Self::Config, @@ -418,9 +432,7 @@ impl - SuperCircuit -{ +impl SuperCircuit { /// From the witness data, generate a SuperCircuit instance with all of the /// sub-circuits filled with their corresponding witnesses. /// @@ -430,6 +442,7 @@ impl Result<(u32, Self, Vec>, CircuitInputBuilder), bus_mapping::Error> { let block_data = BlockData::new_from_geth_data_with_params(geth_data.clone(), circuits_params); @@ -438,7 +451,7 @@ impl Result<(u32, Self, Vec>), bus_mapping::Error> { let mut block = block_convert(&builder.block, &builder.code_db).unwrap(); - block.randomness = F::from(MOCK_RANDOMNESS); - assert_eq!(block.circuits_params.max_txs, MAX_TXS); - assert_eq!(block.circuits_params.max_calldata, MAX_CALLDATA); + block.randomness = mock_randomness; let (_, rows_needed) = Self::min_num_rows_block(&block); let k = log2_ceil(Self::unusable_rows() + rows_needed); log::debug!("super circuit uses k = {}", k); - let circuit = - SuperCircuit::<_, MAX_TXS, MAX_CALLDATA, MOCK_RANDOMNESS>::new_from_block(&block); + let circuit = SuperCircuit::new_from_block(&block); let instance = circuit.instance(); Ok((k, circuit, instance)) diff --git a/zkevm-circuits/src/super_circuit/test.rs b/zkevm-circuits/src/super_circuit/test.rs index 989d143958..697da5cb0c 100644 --- a/zkevm-circuits/src/super_circuit/test.rs +++ b/zkevm-circuits/src/super_circuit/test.rs @@ -12,23 +12,20 @@ use eth_types::{address, bytecode, geth_types::GethData, Word}; #[test] fn super_circuit_degree() { let mut cs = ConstraintSystem::::default(); - SuperCircuit::<_, 1, 32, 0x100>::configure(&mut cs); + let params = SuperCircuitParams { + max_txs: 1, + max_calldata: 32, + mock_randomness: Fr::from(0x100), + }; + SuperCircuit::configure_with_params(&mut cs, params); log::info!("super circuit degree: {}", cs.degree()); log::info!("super circuit minimum_rows: {}", cs.minimum_rows()); assert!(cs.degree() <= 9); } -fn test_super_circuit< - const MAX_TXS: usize, - const MAX_CALLDATA: usize, - const MOCK_RANDOMNESS: u64, ->( - block: GethData, - circuits_params: CircuitsParams, -) { +fn test_super_circuit(block: GethData, circuits_params: CircuitsParams, mock_randomness: Fr) { let (k, circuit, instance, _) = - SuperCircuit::::build(block, circuits_params) - .unwrap(); + SuperCircuit::::build(block, circuits_params, mock_randomness).unwrap(); let prover = MockProver::run(k, &circuit, instance).unwrap(); let res = prover.verify_par(); if let Err(err) = res { @@ -131,11 +128,9 @@ const TEST_MOCK_RANDOMNESS: u64 = 0x100; #[test] fn serial_test_super_circuit_1tx_1max_tx() { let block = block_1tx(); - const MAX_TXS: usize = 1; - const MAX_CALLDATA: usize = 32; let circuits_params = CircuitsParams { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, + max_txs: 1, + max_calldata: 32, max_rws: 256, max_copy_rows: 256, max_exp_steps: 256, @@ -143,17 +138,15 @@ fn serial_test_super_circuit_1tx_1max_tx() { max_evm_rows: 0, max_keccak_rows: 0, }; - test_super_circuit::(block, circuits_params); + test_super_circuit(block, circuits_params, Fr::from(TEST_MOCK_RANDOMNESS)); } #[ignore] #[test] fn serial_test_super_circuit_1tx_2max_tx() { let block = block_1tx(); - const MAX_TXS: usize = 2; - const MAX_CALLDATA: usize = 32; let circuits_params = CircuitsParams { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, + max_txs: 2, + max_calldata: 32, max_rws: 256, max_copy_rows: 256, max_exp_steps: 256, @@ -161,17 +154,15 @@ fn serial_test_super_circuit_1tx_2max_tx() { max_evm_rows: 0, max_keccak_rows: 0, }; - test_super_circuit::(block, circuits_params); + test_super_circuit(block, circuits_params, Fr::from(TEST_MOCK_RANDOMNESS)); } #[ignore] #[test] fn serial_test_super_circuit_2tx_2max_tx() { let block = block_2tx(); - const MAX_TXS: usize = 2; - const MAX_CALLDATA: usize = 32; let circuits_params = CircuitsParams { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, + max_txs: 2, + max_calldata: 32, max_rws: 256, max_copy_rows: 256, max_exp_steps: 256, @@ -179,5 +170,5 @@ fn serial_test_super_circuit_2tx_2max_tx() { max_evm_rows: 0, max_keccak_rows: 0, }; - test_super_circuit::(block, circuits_params); + test_super_circuit(block, circuits_params, Fr::from(TEST_MOCK_RANDOMNESS)); } diff --git a/zkevm-circuits/src/tx_circuit/dev.rs b/zkevm-circuits/src/tx_circuit/dev.rs index 5ddeb02c34..38f210ad53 100644 --- a/zkevm-circuits/src/tx_circuit/dev.rs +++ b/zkevm-circuits/src/tx_circuit/dev.rs @@ -16,6 +16,7 @@ use log::error; impl Circuit for TxCircuit { type Config = (TxCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index 25dc38022d..cb8ef25caa 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -753,6 +753,7 @@ mod sign_verify_tests { impl Circuit for TestCircuitSignVerify { type Config = TestCircuitSignVerifyConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() diff --git a/zkevm-circuits/src/tx_circuit/test.rs b/zkevm-circuits/src/tx_circuit/test.rs index 1c794d3f86..102b32c11d 100644 --- a/zkevm-circuits/src/tx_circuit/test.rs +++ b/zkevm-circuits/src/tx_circuit/test.rs @@ -12,7 +12,7 @@ use mock::AddrOrWallet; fn tx_circuit_unusable_rows() { assert_eq!( TxCircuit::::unusable_rows(), - unusable_rows::>(), + unusable_rows::>(()), ) } diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index b48555a3e4..2a20e42e34 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -229,9 +229,9 @@ pub(crate) fn get_push_size(byte: u8) -> u64 { /// For circuit with column queried at more than 3 distinct rotation, we can /// calculate the unusable rows as (x - 3) + 6 where x is the number of distinct /// rotation. -pub(crate) fn unusable_rows>() -> usize { +pub(crate) fn unusable_rows>(params: C::Params) -> usize { let mut cs = ConstraintSystem::default(); - C::configure(&mut cs); + C::configure_with_params(&mut cs, params); cs.blinding_factors() + 1 } diff --git a/zkevm-circuits/tests/prover_error.rs b/zkevm-circuits/tests/prover_error.rs index d55ca439d0..ef70f98246 100644 --- a/zkevm-circuits/tests/prover_error.rs +++ b/zkevm-circuits/tests/prover_error.rs @@ -1,8 +1,8 @@ // This file is intended to be used with fixtures generated from zkevm-chain. // Copy the `errors/` directory into the zkevm-circuits git root // as `block` and run via `cargo test -p zkevm-circuits --features test -// prover_error -- --nocapture --ignored`. Change any constant variables like -// `MAX_TXS` to suit your needs. +// prover_error -- --nocapture --ignored`. Change any circuit parameters like +// `max_txs` to suit your needs. use bus_mapping::{circuit_input_builder::CircuitsParams, mock::BlockData}; use env_logger::Env; use eth_types::{ @@ -36,14 +36,12 @@ fn load_json(path: &str) -> Value { #[ignore] fn prover_error() { // change any of these values to your needs - const MAX_TXS: usize = 1; - const MAX_CALLDATA: usize = 256; const MOCK_RANDOMNESS: u64 = 0x100; let k = 19; let chain_id = Word::from(99); let circuit_params = CircuitsParams { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, + max_txs: 1, + max_calldata: 256, max_rws: 16388, ..Default::default() }; @@ -104,8 +102,7 @@ fn prover_error() { block.randomness = Fr::from(MOCK_RANDOMNESS); block }; - let circuit = - SuperCircuit::<_, MAX_TXS, MAX_CALLDATA, MOCK_RANDOMNESS>::new_from_block(&block_witness); + let circuit = SuperCircuit::new_from_block(&block_witness); let res = MockProver::run(k, &circuit, circuit.instance()) .expect("MockProver::run") .verify_par(); From 32d81d983927f74d16634a383696ab3087733f1b Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Thu, 11 May 2023 19:26:05 +0800 Subject: [PATCH 036/102] trait ChallengeSet --- .../src/circuit_tools/cached_region.rs | 103 ++++++++++++++--- .../src/circuit_tools/cell_manager.rs | 25 ++-- zkevm-circuits/src/circuit_tools/gadgets.rs | 14 +-- .../src/circuit_tools/tests/util.rs | 109 ++++++++++++++++-- zkevm-circuits/src/mpt_circuit.rs | 6 +- .../src/mpt_circuit/account_leaf.rs | 6 +- zkevm-circuits/src/mpt_circuit/branch.rs | 6 +- zkevm-circuits/src/mpt_circuit/extension.rs | 6 +- .../src/mpt_circuit/extension_branch.rs | 6 +- zkevm-circuits/src/mpt_circuit/helpers.rs | 50 ++++---- zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs | 18 +-- zkevm-circuits/src/mpt_circuit/start.rs | 6 +- .../src/mpt_circuit/storage_leaf.rs | 6 +- zkevm-circuits/src/table.rs | 6 +- zkevm-circuits/src/util.rs | 10 +- 15 files changed, 269 insertions(+), 108 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools/cached_region.rs b/zkevm-circuits/src/circuit_tools/cached_region.rs index 1fa2b27eb7..fae5d5b1e0 100644 --- a/zkevm-circuits/src/circuit_tools/cached_region.rs +++ b/zkevm-circuits/src/circuit_tools/cached_region.rs @@ -1,12 +1,11 @@ use crate::{ - circuit_tools::cell_manager::{Cell, CellType_}, - util::Challenges + circuit_tools::cell_manager::{Cell, CellType_}, util::query_expression, }; use bus_mapping::state_db::CodeDB; use eth_types::{Field, ToLittleEndian, ToWord, U256}; use halo2_proofs::{ - circuit::{AssignedCell, Region, Value}, - plonk::{Advice, Assigned, Column, Error, Expression, Fixed}, + circuit::{AssignedCell, Region, Value, Layouter}, + plonk::{Advice, Assigned, Column, Error, Expression, Fixed, Challenge, ConstraintSystem, SecondPhase, FirstPhase}, poly::Rotation, }; use itertools::Itertools; @@ -16,20 +15,86 @@ use std::{ use super::cell_manager::TableType; -pub struct CachedRegion<'r, 'b, F: Field> { +pub trait ChallengeSet { + type Expression; + type Value; + + /// Construct `Challenges` by allocating challenges in specific phases. + fn construct(meta: &mut ConstraintSystem) -> Self; + + /// Returns `Expression` of challenges from `ConstraintSystem`. + fn exprs(&self, meta: &mut ConstraintSystem) -> Self::Expression; + + /// Returns `Value` of challenges from `Layouter`. + fn values(&self, layouter: &mut impl Layouter) -> Self::Value; +} + + +// #[derive(Default, Clone, Copy, Debug)] +// pub struct EvmChallenges { +// evm_word: C, +// keccak_input: C, +// lookup_input: C, +// } + +impl ChallengeSet for crate::util::Challenges { + type Expression = crate::util::Challenges>; + type Value = crate::util::Challenges>; + + /// Construct `Challenges` by allocating challenges in specific phases. + fn construct(meta: &mut ConstraintSystem) -> Self { + #[cfg(any(feature = "test", test, feature = "test-circuits"))] + let _dummy_cols = [ + meta.advice_column(), + meta.advice_column_in(SecondPhase), + meta.advice_column_in(halo2_proofs::plonk::ThirdPhase), + ]; + + Self { + evm_word: meta.challenge_usable_after(FirstPhase), + keccak_input: meta.challenge_usable_after(FirstPhase), + lookup_input: meta.challenge_usable_after(SecondPhase), + } + } + + /// Returns `Expression` of challenges from `ConstraintSystem`. + fn exprs(&self, meta: &mut ConstraintSystem) -> Self::Expression { + let [evm_word, keccak_input, lookup_input] = query_expression(meta, |meta| { + [self.evm_word, self.keccak_input, self.lookup_input] + .map(|challenge| meta.query_challenge(challenge)) + }); + crate::util::Challenges { + evm_word, + keccak_input, + lookup_input, + } + } + + /// Returns `Value` of challenges from `Layouter`. + fn values(&self, layouter: &mut impl Layouter) -> Self::Value { + crate::util::Challenges { + evm_word: layouter.get_challenge(self.evm_word), + keccak_input: layouter.get_challenge(self.keccak_input), + lookup_input: layouter.get_challenge(self.lookup_input), + } + } +} + + +pub struct CachedRegion<'r, 'b, F: Field, C: ChallengeSet> { region: &'r mut Region<'b, F>, advice: Vec>, - challenges: &'r Challenges>, + challenges: &'r C::Value, advice_columns: Vec>, width_start: usize, height_start: usize, } -impl<'r, 'b, F: Field> CachedRegion<'r, 'b, F> { +impl<'r, 'b, F: Field, C: ChallengeSet> CachedRegion<'r, 'b, F, C> { /// New cached region pub(crate) fn new( region: &'r mut Region<'b, F>, - challenges: &'r Challenges>, + challenges: &'r C::Value, advice_columns: Vec>, height: usize, height_start: usize, @@ -132,18 +197,18 @@ impl<'r, 'b, F: Field> CachedRegion<'r, 'b, F> { [(((row_index - self.height_start) as i32) + rotation.0) as usize] } - pub fn challenges(&self) -> &Challenges> { + pub fn challenges(&self) -> &C::Value { self.challenges } - pub fn word_rlc(&self, n: U256) -> Value { - self.challenges - .evm_word() - .map(|r| rlc::value(&n.to_le_bytes(), r)) - } - pub fn empty_code_hash_rlc(&self) -> Value { - self.word_rlc(CodeDB::empty_code_hash().to_word()) - } + // pub fn word_rlc(&self, n: U256) -> Value { + // self.challenges + // .evm_word() + // .map(|r| rlc::value(&n.to_le_bytes(), r)) + // } + // pub fn empty_code_hash_rlc(&self) -> Value { + // self.word_rlc(CodeDB::empty_code_hash().to_word()) + // } /// Constrains a cell to have a constant value. /// @@ -178,9 +243,9 @@ impl Hash for StoredExpression { } impl StoredExpression { - pub fn assign( + pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, ) -> Result, Error> { let value = self.expr.evaluate( diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index c6850a6f7c..2cb88fa345 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -1,6 +1,6 @@ //! Cell manager use crate::util::{Expr, query_expression}; -use crate::circuit_tools::{table::LookupTable, cached_region::CachedRegion}; +use crate::circuit_tools::{table::LookupTable, cached_region::{CachedRegion, ChallengeSet}}; use eth_types::Field; use halo2_proofs::{ @@ -41,9 +41,9 @@ impl Cell { } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, value: F, ) -> Result, Error> { @@ -60,9 +60,9 @@ impl Cell { ) } - pub(crate) fn assign_value( + pub(crate) fn assign_value>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, value: Value, ) -> Result, Error> { @@ -225,6 +225,17 @@ impl PhaseConfig { } impl CellManager { + + // 一步到位 + pub(crate) fn new_( + meta: &mut ConstraintSystem, + max_height: usize, + max_width: usize, + phase_config: PhaseConfig, + ) -> Self { + todo!() + } + pub(crate) fn new( meta: &mut ConstraintSystem, // meta只出现一次,new的时候把所有cover的cells都query一遍 height: usize, // 拿到 Expr 存起来,后面 cb.query_cell 直接给对应格子的 Expr @@ -260,6 +271,7 @@ impl CellManager { // Mark columns used for lookups in Phase3 for (table, count) in &phase_config.phase3 { for _ in 0usize..*count { + assert_eq!(advices[column_idx].column_type().phase(), 2u8); columns[column_idx].cell_type = CellType_::Lookup(table.clone()); column_idx += 1; } @@ -267,13 +279,13 @@ impl CellManager { // Mark columns used for Phase2 constraints for _ in 0..phase_config.phase2 { + assert_eq!(advices[column_idx].column_type().phase(), 1u8); columns[column_idx].cell_type = CellType_::StoragePhase2; column_idx += 1; } // Mark columns used for byte lookup for _ in 0..phase_config.phase1 { - columns[column_idx].cell_type = CellType_::LookupByte; assert_eq!(advices[column_idx].column_type().phase(), 0); column_idx += 1; } @@ -286,7 +298,6 @@ impl CellManager { } - Self { width, height, diff --git a/zkevm-circuits/src/circuit_tools/gadgets.rs b/zkevm-circuits/src/circuit_tools/gadgets.rs index fbcf624881..5727480491 100644 --- a/zkevm-circuits/src/circuit_tools/gadgets.rs +++ b/zkevm-circuits/src/circuit_tools/gadgets.rs @@ -7,7 +7,7 @@ use halo2_proofs::{ use crate::evm_circuit::util::{from_bytes, pow_of_two}; -use super::{cell_manager::{Cell, TableType}, constraint_builder::ConstraintBuilder, cached_region::CachedRegion}; +use super::{cell_manager::{Cell, TableType}, constraint_builder::ConstraintBuilder, cached_region::{CachedRegion, ChallengeSet}}; /// Returns `1` when `value == 0`, and returns `0` otherwise. #[derive(Clone, Debug, Default)] @@ -38,9 +38,9 @@ impl IsZeroGadget { self.is_zero.as_ref().unwrap().clone() } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, value: F, ) -> Result { @@ -75,9 +75,9 @@ impl IsEqualGadget { self.is_zero.expr() } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, lhs: F, rhs: F, @@ -131,9 +131,9 @@ impl LtGadget { self.lt.as_ref().unwrap().expr() } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, lhs: F, rhs: F, diff --git a/zkevm-circuits/src/circuit_tools/tests/util.rs b/zkevm-circuits/src/circuit_tools/tests/util.rs index 2ccbf53593..05c0784394 100644 --- a/zkevm-circuits/src/circuit_tools/tests/util.rs +++ b/zkevm-circuits/src/circuit_tools/tests/util.rs @@ -1,5 +1,7 @@ +use std::rc::Rc; use std::vec; +use crate::circuit_tools::cached_region::{self, ChallengeSet}; use crate::circuit_tools::cell_manager::{Cell, CellManager, PhaseConfig, SingleTable, TableType}; use crate::circuit_tools::constraint_builder::ConstraintBuilder; use crate::circuit_tools::memory::Memory; @@ -8,7 +10,8 @@ use crate::circuit_tools::{table::LookupTable, cached_region::CachedRegion}; use eth_types::Field; use gadgets::util::Scalar; -use halo2_proofs::plonk::Any; +use halo2_proofs::circuit::{SimpleFloorPlanner, layouter, Layouter, Region}; +use halo2_proofs::plonk::{Any, Circuit, FirstPhase, Challenge, SecondPhase, ThirdPhase}; use halo2_proofs::{ circuit::{AssignedCell, Value}, plonk::{ConstraintSystem, Advice, Column, Error, Expression, VirtualCells}, @@ -44,6 +47,7 @@ impl LookupTable for TestTable { } } +#[derive(Clone)] pub struct TestConfig { pub(crate) q_count: Column, pub(crate) cell_columns: Vec>, @@ -52,14 +56,21 @@ pub struct TestConfig { impl TestConfig { - pub fn new(meta: &mut ConstraintSystem, table: TestTable) -> Self { + pub fn new( + meta: &mut ConstraintSystem, + table: TestTable, + r1: Challenge + ) -> Self { // Get columns - let q_count = meta.advice_column(); - let cell_columns = (0..10).map(|_| meta.advice_column()).collect::>(); + let q_count = meta.advice_column_in(FirstPhase); + let cell_columns: Vec> = (0..2).map(|_| meta.advice_column_in(ThirdPhase)) + .chain((3..5).map(|_| meta.advice_column_in(SecondPhase))) + .chain((6..9).map(|_| meta.advice_column())) + .collect(); // Init cell manager and constraint builder - let phase_config: PhaseConfig = PhaseConfig::new::(vec![&table], 1, 1); + let phase_config: PhaseConfig = PhaseConfig::new::(vec![&table], 2, 3); let mut cm = CellManager::new( meta, CM_HEIGHT, @@ -71,7 +82,11 @@ impl TestConfig { let mut cb = ConstraintBuilder::new(MAX_DEG, Some(cm)); // Init Gadgets - let cell_gadget = CellGadget::configure(&mut cb); + let cell_gadget = CellGadget::configure( + &mut cb, + // Convert Challenge into Expression + query_expression(meta, |meta| meta.query_challenge(r1)) + ); Self { q_count, cell_columns, @@ -79,11 +94,27 @@ impl TestConfig { } } + pub fn assign( + &self, + layouter: &mut impl Layouter, + r1: Value, + ) -> Result<(), Error> { + // layouter.assign_region( + // || "cell gadget", + // |mut region| { + // let cached_region = cached_region::CachedRegion::new(&mut region); + // self.cell_gadget.assign(&mut region, 0, r1) + // }, + // ) + unimplemented!() + } + } #[derive(Clone, Debug, Default)] pub struct CellGadget { - // a + b == c + // a + r1 * b == c + // where r1 is phase1 challenge // a == d a: Cell, b: Cell, @@ -91,31 +122,85 @@ pub struct CellGadget { d: Cell, } + impl CellGadget { - pub fn configure(cb: &mut ConstraintBuilder) -> Self { + pub fn configure(cb: &mut ConstraintBuilder, r1: Expression) -> Self { let a = cb.query_cell(); let b = cb.query_cell(); - let c = cb.query_cell(); + let c = cb.query_byte(); let d = cb.query_cell(); circuit!([meta, cb], { require!((a, b) => @format!("test_lookup")); - require!(c => a.expr() + b.expr()); + require!(c => a.expr() + b.expr() * r1); require!(a => d.expr()); }); CellGadget { a, b, c, d } } - pub fn assign(&self, region: &mut CachedRegion<'_, '_, F>, offset: usize) -> Result<(), Error>{ + pub fn assign>( + &self, + region: &mut CachedRegion<'_, '_, F, C>, + offset: usize, + r1: Value + ) -> Result<(), Error>{ + + self.a.assign(region, offset, 2u64.scalar())?; + self.b.assign(region, offset, 3u64.scalar())?; + + self.c.assign( + region, + offset, + Value::known(2u64.scalar()) + Value::known(2u64.scalar()) * r1.scalar() + )?; + assign!(region, (self.a.column(), offset) => 2u64.scalar())?; assign!(region, (self.b.column(), offset) => 3u64.scalar())?; - assign!(region, (self.c.column(), offset) => 5u64.scalar())?; + assign!(region, (self.c.column(), offset) => 2u64.scalar() + 3u64.scalar() * r1)?; assign!(region, (self.d.column(), offset) => 2u64.scalar())?; + + region.get_advice(1, 1, Rotation::cur()); Ok(()) } } +struct TestCircuit { + config: TestConfig, +} + +impl Circuit for TestCircuit { + type Config = (TestConfig, Challenge); + type FloorPlanner = SimpleFloorPlanner; + + + fn without_witnesses(&self) -> Self { + unimplemented!() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + + // Build the table and challenge outside + // since zkevm use them accross circuits + let table = TestTable { + a: meta.advice_column(), + b: meta.advice_column(), + }; + let r1 = meta.challenge_usable_after(FirstPhase); + + let config = TestConfig::new(meta, table, r1); + (Self { config }, r1) + } + + fn synthesize( + &self, + (config, r1): Self::Config, + layouter: impl halo2_proofs::circuit::Layouter + ) -> Result<(), Error> { + let r1 = layouter.get_challenge(r1); + config.assign(&mut layouter, r1) + } +} #[test] fn test() { diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 1bdd88ff1c..5ac78fa0d3 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -41,7 +41,7 @@ use crate::{ start::StartConfig, storage_leaf::StorageLeafConfig, }, - circuit_tools::{table::LookupTable, cell_manager::PhaseConfig}, + circuit_tools::{table::LookupTable, cell_manager::PhaseConfig, cached_region::ChallengeSet}, table::{KeccakTable, MPTProofType, MptTable}, util::Challenges, }; @@ -332,7 +332,7 @@ impl MPTConfig { } /// Make the assignments to the MPTCircuit - pub fn assign( + pub fn assign>( &self, layouter: &mut impl Layouter, nodes: &[Node], @@ -355,7 +355,7 @@ impl MPTConfig { for node in nodes.iter() { // Assign bytes let mut rlp_values = Vec::new(); - let mut cahced_region = CachedRegion::new( + let mut cahced_region: CachedRegion = CachedRegion::new( &mut region, challenges, self.managed_columns.clone(), diff --git a/zkevm-circuits/src/mpt_circuit/account_leaf.rs b/zkevm-circuits/src/mpt_circuit/account_leaf.rs index ab1e4daa6f..2994f50aa0 100644 --- a/zkevm-circuits/src/mpt_circuit/account_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/account_leaf.rs @@ -17,7 +17,7 @@ use crate::{ circuit_tools::{ cell_manager::Cell, constraint_builder::{RLCChainable, RLCable, RLCableValue}, - gadgets::IsEqualGadget, cached_region::CachedRegion, + gadgets::IsEqualGadget, cached_region::{CachedRegion, ChallengeSet}, }, mpt_circuit::{ helpers::{ @@ -357,9 +357,9 @@ impl AccountLeafConfig { config } - pub fn assign( + pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, ctx: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/branch.rs b/zkevm-circuits/src/mpt_circuit/branch.rs index 85569e191d..37cbfef7a2 100644 --- a/zkevm-circuits/src/mpt_circuit/branch.rs +++ b/zkevm-circuits/src/mpt_circuit/branch.rs @@ -13,7 +13,7 @@ use super::{ }; use crate::{ circuit, - circuit_tools::{cell_manager::Cell, constraint_builder::RLCChainable, gadgets::LtGadget, cached_region::CachedRegion}, + circuit_tools::{cell_manager::Cell, constraint_builder::RLCChainable, gadgets::LtGadget, cached_region::{CachedRegion, ChallengeSet}}, mpt_circuit::{ helpers::{nibble_rlc, Indexable}, param::{HASH_WIDTH, RLP_NIL}, @@ -269,9 +269,9 @@ impl BranchGadget { self.post_state.as_ref().unwrap().clone() } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, _mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/extension.rs b/zkevm-circuits/src/mpt_circuit/extension.rs index 972a5e3830..10b713b416 100644 --- a/zkevm-circuits/src/mpt_circuit/extension.rs +++ b/zkevm-circuits/src/mpt_circuit/extension.rs @@ -12,7 +12,7 @@ use super::{ }; use crate::{ circuit, - circuit_tools::{cell_manager::Cell, constraint_builder::RLCChainable, gadgets::LtGadget, cached_region::CachedRegion}, + circuit_tools::{cell_manager::Cell, constraint_builder::RLCChainable, gadgets::LtGadget, cached_region::{CachedRegion, ChallengeSet}}, mpt_circuit::{ helpers::{ ext_key_rlc_calc_value, ext_key_rlc_expr, num_nibbles, Indexable, KeyData, ParentData, @@ -178,9 +178,9 @@ impl ExtensionGadget { self.post_state.as_ref().unwrap().clone() } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, _mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/extension_branch.rs b/zkevm-circuits/src/mpt_circuit/extension_branch.rs index ac1f329418..1d6fb7189c 100644 --- a/zkevm-circuits/src/mpt_circuit/extension_branch.rs +++ b/zkevm-circuits/src/mpt_circuit/extension_branch.rs @@ -14,7 +14,7 @@ use super::{ }; use crate::{ circuit, - circuit_tools::{cell_manager::Cell, cached_region::CachedRegion}, + circuit_tools::{cell_manager::Cell, cached_region::{CachedRegion, ChallengeSet}}, mpt_circuit::{ helpers::{key_memory, parent_memory, Indexable, KeyData, ParentData}, witness_row::ExtensionBranchRowType, @@ -181,9 +181,9 @@ impl ExtensionBranchConfig { config } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index 18573df644..88fba84b18 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -6,7 +6,7 @@ use crate::{ ConstraintBuilder, RLCChainable, RLCChainableValue, RLCable, RLCableValue, }, gadgets::IsEqualGadget, - memory::MemoryBank, cached_region::CachedRegion, + memory::MemoryBank, cached_region::{CachedRegion, ChallengeSet}, }, matchw, mpt_circuit::{ @@ -96,9 +96,9 @@ impl LeafKeyGadget { }) } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, bytes: &[u8], ) -> Result { @@ -268,9 +268,9 @@ impl ListKeyGadget { } } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, list_bytes: &[u8], key_item: &RLPItemWitness, @@ -408,8 +408,8 @@ impl KeyData { ] } - pub(crate) fn witness_store( - _region: &mut CachedRegion<'_, '_, F>, + pub(crate) fn witness_store>( + _region: &mut CachedRegion<'_, '_, F, C>, offset: usize, memory: &mut MemoryBank, rlc: F, @@ -434,9 +434,9 @@ impl KeyData { Ok(()) } - pub(crate) fn witness_load( + pub(crate) fn witness_load>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, memory: &MemoryBank, load_offset: usize, @@ -521,8 +521,8 @@ impl ParentData { memory.store(cb, &[rlc, is_root, is_placeholder, drifted_parent_rlc]); } - pub(crate) fn witness_store( - _region: &mut CachedRegion<'_, '_, F>, + pub(crate) fn witness_store>( + _region: &mut CachedRegion<'_, '_, F, C>, offset: usize, memory: &mut MemoryBank, rlc: F, @@ -542,9 +542,9 @@ impl ParentData { Ok(()) } - pub(crate) fn witness_load( + pub(crate) fn witness_load>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, memory: &MemoryBank, load_offset: usize, @@ -622,8 +622,8 @@ impl MainData { memory.store(cb, &values); } - pub(crate) fn witness_store( - _region: &mut CachedRegion<'_, '_, F>, + pub(crate) fn witness_store>( + _region: &mut CachedRegion<'_, '_, F, C>, offset: usize, memory: &mut MemoryBank, proof_type: usize, @@ -644,9 +644,9 @@ impl MainData { Ok(()) } - pub(crate) fn witness_load( + pub(crate) fn witness_load>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, memory: &MemoryBank, load_offset: usize, @@ -843,9 +843,9 @@ impl IsEmptyTreeGadget { or::expr(&[self.is_in_empty_trie.expr(), self.is_in_empty_branch.expr()]) } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, parent_rlc: F, r: F, @@ -920,9 +920,9 @@ impl DriftedGadget { }) } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, parent_data: &[ParentDataWitness], drifted_list_bytes: &[u8], @@ -988,9 +988,9 @@ impl WrongGadget { }) } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, is_non_existing: bool, key_rlc: &[F], @@ -1079,9 +1079,9 @@ impl MainRLPGadget { }) } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, bytes: &[u8], r: F, diff --git a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs index 920f3bec4a..7559acdbd5 100644 --- a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs +++ b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs @@ -4,7 +4,7 @@ use crate::{ circuit, circuit_tools::{ cell_manager::{Cell}, - constraint_builder::{ConstraintBuilder, RLCable, RLCableValue}, cached_region::CachedRegion, + constraint_builder::{ConstraintBuilder, RLCable, RLCableValue}, cached_region::{CachedRegion, ChallengeSet}, }, matchw, mpt_circuit::param::{RLP_LIST_LONG, RLP_LIST_SHORT, RLP_SHORT}, @@ -49,9 +49,9 @@ impl RLPListGadget { } } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, bytes: &[u8], ) -> Result { @@ -233,9 +233,9 @@ impl RLPListDataGadget { } } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, list_bytes: &[u8], ) -> Result { @@ -280,9 +280,9 @@ impl RLPValueGadget { } } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, bytes: &[u8], ) -> Result { @@ -574,9 +574,9 @@ impl RLPItemGadget { } } - pub(crate) fn assign( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, bytes: &[u8], ) -> Result { diff --git a/zkevm-circuits/src/mpt_circuit/start.rs b/zkevm-circuits/src/mpt_circuit/start.rs index d8511ccb75..eb4b38778b 100644 --- a/zkevm-circuits/src/mpt_circuit/start.rs +++ b/zkevm-circuits/src/mpt_circuit/start.rs @@ -6,7 +6,7 @@ use super::{ use crate::{ circuit, circuit_tools::{ - cell_manager::Cell, cached_region::CachedRegion, + cell_manager::Cell, cached_region::{CachedRegion, ChallengeSet}, }, mpt_circuit::{ helpers::{ @@ -81,9 +81,9 @@ impl StartConfig { config } - pub fn assign( + pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, _ctx: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs index 61c5838bc9..cdf05cb4b5 100644 --- a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs @@ -11,7 +11,7 @@ use crate::{ circuit_tools::{ cell_manager::Cell, constraint_builder::RLCChainable, - gadgets::{IsEqualGadget, LtGadget}, cached_region::CachedRegion, + gadgets::{IsEqualGadget, LtGadget}, cached_region::{CachedRegion, ChallengeSet}, }, mpt_circuit::{ helpers::{ @@ -257,9 +257,9 @@ impl StorageLeafConfig { config } - pub fn assign( + pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, ctx: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 74a6340d4d..ecf71d16c3 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -2,7 +2,7 @@ use crate::{ circuit, - circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::TableType, cached_region::CachedRegion}, + circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::TableType, cached_region::{CachedRegion, ChallengeSet}}, copy_circuit::number_or_hash_to_field, evm_circuit::util::rlc, exp_circuit::{OFFSET_INCREMENT, ROWS_PER_STEP}, @@ -695,9 +695,9 @@ impl MptTable { Ok(()) } - pub(crate) fn assign_cached( + pub(crate) fn assign_cached>( &self, - region: &mut CachedRegion<'_, '_, F>, + region: &mut CachedRegion<'_, '_, F, C>, offset: usize, row: &MptUpdateRow>, ) -> Result<(), Error> { diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index d893756b21..c5338386db 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -32,9 +32,9 @@ pub(crate) fn random_linear_combine_word(bytes: [u8; 32], randomness: /// All challenges used in `SuperCircuit`. #[derive(Default, Clone, Copy, Debug)] pub struct Challenges { - evm_word: T, - keccak_input: T, - lookup_input: T, + pub evm_word: T, + pub keccak_input: T, + pub lookup_input: T, } impl Challenges { @@ -94,8 +94,8 @@ impl Challenges { } /// Returns the challenges indexed by the challenge index - pub fn indexed(&self) -> [&T; 3] { - [&self.evm_word, &self.keccak_input, &self.lookup_input] + pub fn indexed(&self) -> Vec<&T> { + vec![&self.evm_word, &self.keccak_input, &self.lookup_input] } pub(crate) fn mock(evm_word: T, keccak_input: T, lookup_input: T) -> Self { From bfdf4d45ff6c5539ae00b49591184fa043e14a0d Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 12 May 2023 11:12:41 +0800 Subject: [PATCH 037/102] compiled ChallengeSet --- rust-toolchain | 2 +- .../src/circuit_tools/cached_region.rs | 84 +++++-------------- zkevm-circuits/src/circuit_tools/gadgets.rs | 2 +- .../src/circuit_tools/tests/util.rs | 12 +-- zkevm-circuits/src/lib.rs | 2 +- zkevm-circuits/src/mpt_circuit.rs | 4 +- zkevm-circuits/src/mpt_circuit/branch.rs | 2 +- zkevm-circuits/src/mpt_circuit/extension.rs | 2 +- .../src/mpt_circuit/extension_branch.rs | 2 +- zkevm-circuits/src/mpt_circuit/helpers.rs | 2 +- zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs | 2 +- zkevm-circuits/src/mpt_circuit/start.rs | 2 +- 12 files changed, 39 insertions(+), 79 deletions(-) diff --git a/rust-toolchain b/rust-toolchain index 24b6d11f20..7d80f3030d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2022-08-23 +nightly-2022-08-23 \ No newline at end of file diff --git a/zkevm-circuits/src/circuit_tools/cached_region.rs b/zkevm-circuits/src/circuit_tools/cached_region.rs index fae5d5b1e0..71b9a8491b 100644 --- a/zkevm-circuits/src/circuit_tools/cached_region.rs +++ b/zkevm-circuits/src/circuit_tools/cached_region.rs @@ -1,7 +1,6 @@ use crate::{ circuit_tools::cell_manager::{Cell, CellType_}, util::query_expression, }; -use bus_mapping::state_db::CodeDB; use eth_types::{Field, ToLittleEndian, ToWord, U256}; use halo2_proofs::{ circuit::{AssignedCell, Region, Value, Layouter}, @@ -15,76 +14,35 @@ use std::{ use super::cell_manager::TableType; -pub trait ChallengeSet { - type Expression; - type Value; - - /// Construct `Challenges` by allocating challenges in specific phases. - fn construct(meta: &mut ConstraintSystem) -> Self; - - /// Returns `Expression` of challenges from `ConstraintSystem`. - fn exprs(&self, meta: &mut ConstraintSystem) -> Self::Expression; - - /// Returns `Value` of challenges from `Layouter`. - fn values(&self, layouter: &mut impl Layouter) -> Self::Value; +trait Indexd { + fn indexed(&self) -> Vec<&T>; } - -// #[derive(Default, Clone, Copy, Debug)] -// pub struct EvmChallenges { -// evm_word: C, -// keccak_input: C, -// lookup_input: C, -// } - -impl ChallengeSet for crate::util::Challenges { - type Expression = crate::util::Challenges>; - type Value = crate::util::Challenges>; - - /// Construct `Challenges` by allocating challenges in specific phases. - fn construct(meta: &mut ConstraintSystem) -> Self { - #[cfg(any(feature = "test", test, feature = "test-circuits"))] - let _dummy_cols = [ - meta.advice_column(), - meta.advice_column_in(SecondPhase), - meta.advice_column_in(halo2_proofs::plonk::ThirdPhase), - ]; - - Self { - evm_word: meta.challenge_usable_after(FirstPhase), - keccak_input: meta.challenge_usable_after(FirstPhase), - lookup_input: meta.challenge_usable_after(SecondPhase), - } - } - - /// Returns `Expression` of challenges from `ConstraintSystem`. - fn exprs(&self, meta: &mut ConstraintSystem) -> Self::Expression { - let [evm_word, keccak_input, lookup_input] = query_expression(meta, |meta| { - [self.evm_word, self.keccak_input, self.lookup_input] - .map(|challenge| meta.query_challenge(challenge)) - }); - crate::util::Challenges { - evm_word, - keccak_input, - lookup_input, - } +impl Indexd for crate::util::Challenges { + fn indexed(&self) -> Vec<&T> { + vec![&self.evm_word, &self.keccak_input, &self.lookup_input] } +} +pub trait ChallengeSet { + fn indexed(&self) -> Vec<&Value>; +} - /// Returns `Value` of challenges from `Layouter`. - fn values(&self, layouter: &mut impl Layouter) -> Self::Value { - crate::util::Challenges { - evm_word: layouter.get_challenge(self.evm_word), - keccak_input: layouter.get_challenge(self.keccak_input), - lookup_input: layouter.get_challenge(self.lookup_input), - } +impl ChallengeSet for crate::util::Challenges> { + fn indexed(&self) -> Vec<&Value> { + vec![&self.evm_word, &self.keccak_input, &self.lookup_input] } } +// pub struct EvmChallenges { +// pub evm_word: T, +// pub keccak_input: T, +// pub lookup_input: T, +// } pub struct CachedRegion<'r, 'b, F: Field, C: ChallengeSet> { region: &'r mut Region<'b, F>, advice: Vec>, - challenges: &'r C::Value, + challenges: &'r C, advice_columns: Vec>, width_start: usize, height_start: usize, @@ -94,7 +52,7 @@ impl<'r, 'b, F: Field, C: ChallengeSet> CachedRegion<'r, 'b, F, C> { /// New cached region pub(crate) fn new( region: &'r mut Region<'b, F>, - challenges: &'r C::Value, + challenges: &'r C, advice_columns: Vec>, height: usize, height_start: usize, @@ -197,10 +155,11 @@ impl<'r, 'b, F: Field, C: ChallengeSet> CachedRegion<'r, 'b, F, C> { [(((row_index - self.height_start) as i32) + rotation.0) as usize] } - pub fn challenges(&self) -> &C::Value { + pub fn challenges(&self) -> &C { self.challenges } + // pub fn word_rlc(&self, n: U256) -> Value { // self.challenges // .evm_word() @@ -210,6 +169,7 @@ impl<'r, 'b, F: Field, C: ChallengeSet> CachedRegion<'r, 'b, F, C> { // self.word_rlc(CodeDB::empty_code_hash().to_word()) // } + /// Constrains a cell to have a constant value. /// /// Returns an error if the cell is in a column where equality has not been diff --git a/zkevm-circuits/src/circuit_tools/gadgets.rs b/zkevm-circuits/src/circuit_tools/gadgets.rs index 5727480491..6e0f3cc189 100644 --- a/zkevm-circuits/src/circuit_tools/gadgets.rs +++ b/zkevm-circuits/src/circuit_tools/gadgets.rs @@ -2,7 +2,7 @@ use eth_types::Field; use gadgets::util::Expr; use halo2_proofs::{ - plonk::{Error, Expression}, + plonk::{Error, Expression}, circuit::Value, }; use crate::evm_circuit::util::{from_bytes, pow_of_two}; diff --git a/zkevm-circuits/src/circuit_tools/tests/util.rs b/zkevm-circuits/src/circuit_tools/tests/util.rs index 05c0784394..059b40affe 100644 --- a/zkevm-circuits/src/circuit_tools/tests/util.rs +++ b/zkevm-circuits/src/circuit_tools/tests/util.rs @@ -147,11 +147,11 @@ impl CellGadget { self.a.assign(region, offset, 2u64.scalar())?; self.b.assign(region, offset, 3u64.scalar())?; - self.c.assign( - region, - offset, - Value::known(2u64.scalar()) + Value::known(2u64.scalar()) * r1.scalar() - )?; + // self.c.assign( + // region, + // offset, + // 2u64.scalar() + 3u64.scalar() * r1 + // )?; assign!(region, (self.a.column(), offset) => 2u64.scalar())?; assign!(region, (self.b.column(), offset) => 3u64.scalar())?; @@ -189,7 +189,7 @@ impl Circuit for TestCircuit { let r1 = meta.challenge_usable_after(FirstPhase); let config = TestConfig::new(meta, table, r1); - (Self { config }, r1) + (config, r1) } fn synthesize( diff --git a/zkevm-circuits/src/lib.rs b/zkevm-circuits/src/lib.rs index c68a4a9e58..34fcd75bec 100644 --- a/zkevm-circuits/src/lib.rs +++ b/zkevm-circuits/src/lib.rs @@ -13,7 +13,7 @@ #![allow(clippy::upper_case_acronyms)] // Catch documentation errors caused by code changes. #![deny(rustdoc::broken_intra_doc_links)] -#![deny(missing_docs)] +// #![deny(missing_docs)] #![deny(unsafe_code)] #![deny(clippy::debug_assert_with_mut_call)] diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 5ac78fa0d3..b18c30e3ff 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -332,7 +332,7 @@ impl MPTConfig { } /// Make the assignments to the MPTCircuit - pub fn assign>( + pub fn assign( &self, layouter: &mut impl Layouter, nodes: &[Node], @@ -355,7 +355,7 @@ impl MPTConfig { for node in nodes.iter() { // Assign bytes let mut rlp_values = Vec::new(); - let mut cahced_region: CachedRegion = CachedRegion::new( + let mut cahced_region = CachedRegion::new( &mut region, challenges, self.managed_columns.clone(), diff --git a/zkevm-circuits/src/mpt_circuit/branch.rs b/zkevm-circuits/src/mpt_circuit/branch.rs index 37cbfef7a2..815af2a577 100644 --- a/zkevm-circuits/src/mpt_circuit/branch.rs +++ b/zkevm-circuits/src/mpt_circuit/branch.rs @@ -1,7 +1,7 @@ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - plonk::{Error, Expression, VirtualCells}, + plonk::{Error, Expression, VirtualCells}, circuit::Value, }; use super::{ diff --git a/zkevm-circuits/src/mpt_circuit/extension.rs b/zkevm-circuits/src/mpt_circuit/extension.rs index 10b713b416..c7b3904950 100644 --- a/zkevm-circuits/src/mpt_circuit/extension.rs +++ b/zkevm-circuits/src/mpt_circuit/extension.rs @@ -1,7 +1,7 @@ use eth_types::Field; use gadgets::util::{pow, Scalar}; use halo2_proofs::{ - plonk::{Error, Expression, VirtualCells}, + plonk::{Error, Expression, VirtualCells}, circuit::Value, }; use super::{ diff --git a/zkevm-circuits/src/mpt_circuit/extension_branch.rs b/zkevm-circuits/src/mpt_circuit/extension_branch.rs index 1d6fb7189c..749e1afa72 100644 --- a/zkevm-circuits/src/mpt_circuit/extension_branch.rs +++ b/zkevm-circuits/src/mpt_circuit/extension_branch.rs @@ -1,7 +1,7 @@ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - plonk::{Error, VirtualCells}, + plonk::{Error, VirtualCells}, circuit::Value, }; use super::{ diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index 88fba84b18..0a7226d0bd 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -18,7 +18,7 @@ use crate::{ use eth_types::Field; use gadgets::util::{or, pow, Scalar}; use halo2_proofs::{ - plonk::{Error, Expression, VirtualCells}, + plonk::{Error, Expression, VirtualCells}, circuit::Value, }; use super::{ diff --git a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs index 7559acdbd5..6d485ffaaa 100644 --- a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs +++ b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs @@ -14,7 +14,7 @@ use crate::{ use eth_types::Field; use gadgets::util::{not, pow, Scalar}; use halo2_proofs::{ - plonk::{Error, Expression}, + plonk::{Error, Expression}, circuit::Value, }; use super::param::{KEY_PREFIX_ODD, KEY_TERMINAL_PREFIX_ODD, RLP_LONG}; diff --git a/zkevm-circuits/src/mpt_circuit/start.rs b/zkevm-circuits/src/mpt_circuit/start.rs index eb4b38778b..03fc4880cd 100644 --- a/zkevm-circuits/src/mpt_circuit/start.rs +++ b/zkevm-circuits/src/mpt_circuit/start.rs @@ -19,7 +19,7 @@ use crate::{ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - plonk::{Error, VirtualCells}, + plonk::{Error, VirtualCells}, circuit::Value, }; #[derive(Clone, Debug, Default)] From 156f84747cc28f8dcf7fb7e3b503a51429d5f4b7 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 12 May 2023 11:14:07 +0800 Subject: [PATCH 038/102] clippy --- gadgets/src/util.rs | 2 +- .../src/circuit_tools/cached_region.rs | 8 ++++---- .../src/circuit_tools/cell_manager.rs | 10 +++++----- .../src/circuit_tools/constraint_builder.rs | 8 ++++---- zkevm-circuits/src/circuit_tools/gadgets.rs | 2 +- zkevm-circuits/src/circuit_tools/tests/util.rs | 2 +- zkevm-circuits/src/mpt_circuit.rs | 8 ++++---- zkevm-circuits/src/mpt_circuit/branch.rs | 10 ++++------ zkevm-circuits/src/mpt_circuit/extension.rs | 6 +++--- .../src/mpt_circuit/extension_branch.rs | 2 +- zkevm-circuits/src/mpt_circuit/helpers.rs | 14 +++++++------- zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs | 2 +- zkevm-circuits/src/mpt_circuit/start.rs | 2 +- zkevm-circuits/src/mpt_circuit/witness_row.rs | 18 ++++++++---------- 14 files changed, 45 insertions(+), 49 deletions(-) diff --git a/gadgets/src/util.rs b/gadgets/src/util.rs index 9e5836ca3f..bfb73436bf 100644 --- a/gadgets/src/util.rs +++ b/gadgets/src/util.rs @@ -164,7 +164,7 @@ pub mod pow { pub fn value(value: F, exponent: usize) -> F { let mut result = 1.scalar(); for _ in 0..exponent { - result = result * value; + result *= value; } result } diff --git a/zkevm-circuits/src/circuit_tools/cached_region.rs b/zkevm-circuits/src/circuit_tools/cached_region.rs index 71b9a8491b..b3ba3be262 100644 --- a/zkevm-circuits/src/circuit_tools/cached_region.rs +++ b/zkevm-circuits/src/circuit_tools/cached_region.rs @@ -1,10 +1,10 @@ use crate::{ - circuit_tools::cell_manager::{Cell, CellType_}, util::query_expression, + circuit_tools::cell_manager::{Cell, CellType_}, }; -use eth_types::{Field, ToLittleEndian, ToWord, U256}; +use eth_types::{Field}; use halo2_proofs::{ - circuit::{AssignedCell, Region, Value, Layouter}, - plonk::{Advice, Assigned, Column, Error, Expression, Fixed, Challenge, ConstraintSystem, SecondPhase, FirstPhase}, + circuit::{AssignedCell, Region, Value}, + plonk::{Advice, Assigned, Column, Error, Expression, Fixed}, poly::Rotation, }; use itertools::Itertools; diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index 2cb88fa345..149708c8eb 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -228,10 +228,10 @@ impl CellManager { // 一步到位 pub(crate) fn new_( - meta: &mut ConstraintSystem, - max_height: usize, - max_width: usize, - phase_config: PhaseConfig, + _meta: &mut ConstraintSystem, + _max_height: usize, + _max_width: usize, + _phase_config: PhaseConfig, ) -> Self { todo!() } @@ -272,7 +272,7 @@ impl CellManager { for (table, count) in &phase_config.phase3 { for _ in 0usize..*count { assert_eq!(advices[column_idx].column_type().phase(), 2u8); - columns[column_idx].cell_type = CellType_::Lookup(table.clone()); + columns[column_idx].cell_type = CellType_::Lookup(*table); column_idx += 1; } } diff --git a/zkevm-circuits/src/circuit_tools/constraint_builder.rs b/zkevm-circuits/src/circuit_tools/constraint_builder.rs index 568a8a52a0..94af725a47 100644 --- a/zkevm-circuits/src/circuit_tools/constraint_builder.rs +++ b/zkevm-circuits/src/circuit_tools/constraint_builder.rs @@ -364,7 +364,7 @@ pub(crate) fn merge_values_unsafe( let default_value = 0.expr(); for (idx, value) in merged_values.iter_mut().enumerate() { *value = sum::expr(values.iter().map(|(condition, values)| { - condition.expr() * values.get(idx).unwrap_or_else(|| &default_value).expr() + condition.expr() * values.get(idx).unwrap_or(&default_value).expr() })); } (selector, merged_values) @@ -508,10 +508,10 @@ pub trait ExprResult { impl ExprResult for () { fn add(&self, _other: &Self) -> Self { - () + } fn mul(&self, _other: &Expression) -> Self { - () + } } @@ -639,7 +639,7 @@ impl, I: IntoIterator> RLCChainableValue CellGadget { assign!(region, (self.a.column(), offset) => 2u64.scalar())?; assign!(region, (self.b.column(), offset) => 3u64.scalar())?; - assign!(region, (self.c.column(), offset) => 2u64.scalar() + 3u64.scalar() * r1)?; + // assign!(region, (self.c.column(), offset) => 2u64.scalar() + 3u64.scalar() * r1)?; assign!(region, (self.d.column(), offset) => 2u64.scalar())?; region.get_advice(1, 1, Rotation::cur()); diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index b18c30e3ff..48240bab2c 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -41,7 +41,7 @@ use crate::{ start::StartConfig, storage_leaf::StorageLeafConfig, }, - circuit_tools::{table::LookupTable, cell_manager::PhaseConfig, cached_region::ChallengeSet}, + circuit_tools::{table::LookupTable, cell_manager::PhaseConfig}, table::{KeccakTable, MPTProofType, MptTable}, util::Challenges, }; @@ -207,7 +207,7 @@ impl MPTConfig { memory.allocate(meta, main_memory()); let mut ctx = MPTContext { - mpt_table: mpt_table.clone(), + mpt_table: mpt_table, rlp_item: rlp_item.clone(), challenges: challenges.clone(), r: challenges.keccak_input(), @@ -304,9 +304,9 @@ impl MPTConfig { cb.base.generate_lookups(meta, &ctx.memory.tags()); } else if disable_lookups == 3 { cb.base - .generate_lookups(meta, &vec!["fixed".to_string(), "keccak".to_string()]); + .generate_lookups(meta, &["fixed".to_string(), "keccak".to_string()]); } else if disable_lookups == 4 { - cb.base.generate_lookups(meta, &vec!["keccak".to_string()]); + cb.base.generate_lookups(meta, &["keccak".to_string()]); } println!("num lookups: {}", meta.lookups().len()); diff --git a/zkevm-circuits/src/mpt_circuit/branch.rs b/zkevm-circuits/src/mpt_circuit/branch.rs index 815af2a577..96a579fec1 100644 --- a/zkevm-circuits/src/mpt_circuit/branch.rs +++ b/zkevm-circuits/src/mpt_circuit/branch.rs @@ -1,7 +1,7 @@ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - plonk::{Error, Expression, VirtualCells}, circuit::Value, + plonk::{Error, Expression, VirtualCells}, }; use super::{ @@ -338,12 +338,10 @@ impl BranchGadget { for is_s in [true, false] { mod_node_hash_rlc[is_s.idx()] = if is_placeholder[is_s.idx()] { rlp_values[1 + branch.drifted_index].rlc_content(pv.r) + } else if is_s { + rlp_values[1 + branch.modified_index].rlc_content(pv.r) } else { - if is_s { - rlp_values[1 + branch.modified_index].rlc_content(pv.r) - } else { - rlp_values[0].rlc_content(pv.r) - } + rlp_values[0].rlc_content(pv.r) }; self.mod_rlc[is_s.idx()].assign(region, offset, mod_node_hash_rlc[is_s.idx()])?; } diff --git a/zkevm-circuits/src/mpt_circuit/extension.rs b/zkevm-circuits/src/mpt_circuit/extension.rs index c7b3904950..ac060fe631 100644 --- a/zkevm-circuits/src/mpt_circuit/extension.rs +++ b/zkevm-circuits/src/mpt_circuit/extension.rs @@ -1,7 +1,7 @@ use eth_types::Field; use gadgets::util::{pow, Scalar}; use halo2_proofs::{ - plonk::{Error, Expression, VirtualCells}, circuit::Value, + plonk::{Error, Expression, VirtualCells}, }; use super::{ @@ -163,7 +163,7 @@ impl ExtensionGadget { // Store the post ext state config.post_state = Some(ExtState { - key_rlc: key_rlc, + key_rlc, key_mult: key_data.mult.expr() * config.mult_key.expr(), num_nibbles, is_key_odd, @@ -246,7 +246,7 @@ impl ExtensionGadget { // Key RLC let (key_rlc_ext, _) = ext_key_rlc_calc_value( - rlp_key.key_item.clone(), + rlp_key.key_item, key_data.mult, is_key_part_odd, !*is_key_odd, diff --git a/zkevm-circuits/src/mpt_circuit/extension_branch.rs b/zkevm-circuits/src/mpt_circuit/extension_branch.rs index 749e1afa72..1d6fb7189c 100644 --- a/zkevm-circuits/src/mpt_circuit/extension_branch.rs +++ b/zkevm-circuits/src/mpt_circuit/extension_branch.rs @@ -1,7 +1,7 @@ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - plonk::{Error, VirtualCells}, circuit::Value, + plonk::{Error, VirtualCells}, }; use super::{ diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index 0a7226d0bd..577a019843 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -18,7 +18,7 @@ use crate::{ use eth_types::Field; use gadgets::util::{or, pow, Scalar}; use halo2_proofs::{ - plonk::{Error, Expression, VirtualCells}, circuit::Value, + plonk::{Error, Expression, VirtualCells}, }; use super::{ @@ -226,7 +226,7 @@ pub(crate) fn ext_key_rlc_calc_value( // Check that `nibble_hi` is correct. assert!(*byte == nibble_lo * 16 + nibble_hi); // Collect bytes - (F::from(*nibble_hi as u64) * F::from(16 as u64) * r) + F::from(nibble_lo as u64) + (F::from(*nibble_hi as u64) * F::from(16_u64) * r) + F::from(nibble_lo as u64) }).collect::>()); calc_rlc(&key_bytes, 1.scalar()) }, @@ -752,7 +752,7 @@ pub(crate) fn ext_key_rlc_value( (0.scalar(), 1.scalar()) }; (rlc, key_mult_prev * mult) - .rlc_chain_value(bytes[1..].iter().map(|v| v).collect::>(), r) + .rlc_chain_value(bytes[1..].iter().collect::>(), r) } // Returns the number of nibbles stored in a key value @@ -827,7 +827,7 @@ impl IsEmptyTreeGadget { .iter() .map(|v| v.expr()) .collect::>() - .rlc(&r); + .rlc(r); let is_in_empty_trie = IsEqualGadget::construct(cb, parent_rlc.expr(), empty_root_rlc.expr()); let is_in_empty_branch = IsEqualGadget::construct(cb, parent_rlc.expr(), 0.expr()); @@ -896,7 +896,7 @@ impl DriftedGadget { config.drifted_rlp_key.key_value.clone(), key_mult.expr(), is_key_odd.expr(), - &r + r ); // The key of the drifted leaf needs to match the key of the leaf require!(key_rlc => expected_key_rlc[is_s.idx()]); @@ -907,10 +907,10 @@ impl DriftedGadget { require!(key_num_nibbles.expr() + num_nibbles => KEY_LEN_IN_NIBBLES); // Multiplier after list and key - let mult = config.drifted_rlp_key.rlp_list.rlp_mult(&r) * drifted_item.mult(); + let mult = config.drifted_rlp_key.rlp_list.rlp_mult(r) * drifted_item.mult(); // Complete the drifted leaf rlc by adding the bytes on the value row - let leaf_rlc = (config.drifted_rlp_key.rlc(&r), mult.expr()).rlc_chain(leaf_no_key_rlc[is_s.idx()].expr()); + let leaf_rlc = (config.drifted_rlp_key.rlc(r), mult.expr()).rlc_chain(leaf_no_key_rlc[is_s.idx()].expr()); // The drifted leaf needs to be stored in the branch at `drifted_index`. require!((1, leaf_rlc, config.drifted_rlp_key.rlp_list.num_bytes(), parent_data[is_s.idx()].drifted_parent_rlc.expr()) => @"keccak"); } diff --git a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs index 6d485ffaaa..7559acdbd5 100644 --- a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs +++ b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs @@ -14,7 +14,7 @@ use crate::{ use eth_types::Field; use gadgets::util::{not, pow, Scalar}; use halo2_proofs::{ - plonk::{Error, Expression}, circuit::Value, + plonk::{Error, Expression}, }; use super::param::{KEY_PREFIX_ODD, KEY_TERMINAL_PREFIX_ODD, RLP_LONG}; diff --git a/zkevm-circuits/src/mpt_circuit/start.rs b/zkevm-circuits/src/mpt_circuit/start.rs index 03fc4880cd..eb4b38778b 100644 --- a/zkevm-circuits/src/mpt_circuit/start.rs +++ b/zkevm-circuits/src/mpt_circuit/start.rs @@ -19,7 +19,7 @@ use crate::{ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - plonk::{Error, VirtualCells}, circuit::Value, + plonk::{Error, VirtualCells}, }; #[derive(Clone, Debug, Default)] diff --git a/zkevm-circuits/src/mpt_circuit/witness_row.rs b/zkevm-circuits/src/mpt_circuit/witness_row.rs index cfcbc39767..56d8bce961 100644 --- a/zkevm-circuits/src/mpt_circuit/witness_row.rs +++ b/zkevm-circuits/src/mpt_circuit/witness_row.rs @@ -371,14 +371,12 @@ pub(crate) fn prepare_witness(witness: &mut [MptWitnessRow]) -> Vec 2 } else if is_very_long { 3 + } else if row.get_type() == MptWitnessRowType::ExtensionNodeS { + 0 + } else if is_string { + unreachable!() } else { - if row.get_type() == MptWitnessRowType::ExtensionNodeS { - 0 - } else if is_string { - unreachable!() - } else { - unreachable!() - } + unreachable!() }; // println!("bytes: {:?}", key_bytes); @@ -514,7 +512,7 @@ pub(crate) fn prepare_witness(witness: &mut [MptWitnessRow]) -> Vec node_rows[StartRowType::RootC as usize] = new_row.c(); let start_node = StartNode { - proof_type: new_row.proof_type.clone(), + proof_type: new_row.proof_type, }; let mut node = Node::default(); node.start = Some(start_node); @@ -524,7 +522,7 @@ pub(crate) fn prepare_witness(witness: &mut [MptWitnessRow]) -> Vec if witness[offset].get_type() == MptWitnessRowType::InitBranch { let row_init = witness[offset].to_owned(); - let is_placeholder = row_init.is_placeholder.clone(); + let is_placeholder = row_init.is_placeholder; let is_extension = row_init.is_extension; let modified_index = row_init.modified_index; let mut drifted_index = row_init.drifted_index; @@ -569,7 +567,7 @@ pub(crate) fn prepare_witness(witness: &mut [MptWitnessRow]) -> Vec node.values = node_rows; nodes.push(node); } else if witness[offset].get_type() == MptWitnessRowType::StorageLeafSKey { - let row_key = [&witness[offset + 0], &witness[offset + 2]]; + let row_key = [&witness[offset], &witness[offset + 2]]; let row_value = [&witness[offset + 1], &witness[offset + 3]]; let row_drifted = &witness[offset + 4]; let row_wrong = &witness[offset + 5]; From 0e1d230191d3a1b3ea4b27034c73a545a6e66158 Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Fri, 12 May 2023 12:46:54 +0800 Subject: [PATCH 039/102] Replace Witness.rs's ExecStep with CIP's (#1403) ### Description - We replace ExecStep struct in witness.rs with the one in the Circuit Input Builder. - We add some convenient methods in CIP's ExecStep so that we don't create extra struct fields. - Add `get_rws` method to `witness::Block` to streamline the logic of getting Read-Write records. ### Issue Link Part of #1391 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Rationale - Notes for reviewers, one place that might be error-prone would be the rw_indices. After the cleanup in this PR, we can replace the manual counting of rw indices with something like `evm_circuit::utils::StepRws`. --------- Co-authored-by: Eduard S. --- .../src/circuit_input_builder/execution.rs | 39 +++ bus-mapping/src/operation.rs | 6 + eth-types/src/evm_types.rs | 18 ++ zkevm-circuits/src/evm_circuit.rs | 5 +- zkevm-circuits/src/evm_circuit/execution.rs | 45 ++-- .../src/evm_circuit/execution/add_sub.rs | 8 +- .../src/evm_circuit/execution/addmod.rs | 4 +- .../src/evm_circuit/execution/address.rs | 3 +- .../src/evm_circuit/execution/balance.rs | 8 +- .../src/evm_circuit/execution/begin_tx.rs | 2 +- .../src/evm_circuit/execution/bitwise.rs | 3 +- .../src/evm_circuit/execution/block_ctx.rs | 6 +- .../src/evm_circuit/execution/blockhash.rs | 4 +- .../src/evm_circuit/execution/byte.rs | 4 +- .../src/evm_circuit/execution/calldatacopy.rs | 3 +- .../src/evm_circuit/execution/calldataload.rs | 7 +- .../src/evm_circuit/execution/calldatasize.rs | 2 +- .../src/evm_circuit/execution/caller.rs | 2 +- .../src/evm_circuit/execution/callop.rs | 65 ++--- .../src/evm_circuit/execution/callvalue.rs | 2 +- .../src/evm_circuit/execution/chainid.rs | 2 +- .../src/evm_circuit/execution/codecopy.rs | 2 +- .../src/evm_circuit/execution/codesize.rs | 2 +- .../src/evm_circuit/execution/comparator.rs | 12 +- .../src/evm_circuit/execution/dummy.rs | 6 +- .../src/evm_circuit/execution/dup.rs | 2 +- .../src/evm_circuit/execution/end_block.rs | 4 +- .../src/evm_circuit/execution/end_tx.rs | 10 +- .../execution/error_invalid_jump.rs | 6 +- .../execution/error_invalid_opcode.rs | 2 +- .../evm_circuit/execution/error_oog_call.rs | 34 +-- .../execution/error_oog_constant.rs | 8 +- .../evm_circuit/execution/error_oog_exp.rs | 8 +- .../evm_circuit/execution/error_oog_log.rs | 9 +- .../execution/error_oog_memory_copy.rs | 10 +- .../execution/error_oog_sload_sstore.rs | 17 +- .../execution/error_oog_static_memory.rs | 6 +- .../execution/error_return_data_oo_bound.rs | 6 +- .../src/evm_circuit/execution/error_stack.rs | 2 +- .../execution/error_write_protection.rs | 5 +- .../src/evm_circuit/execution/exp.rs | 3 +- .../src/evm_circuit/execution/extcodecopy.rs | 6 +- .../src/evm_circuit/execution/extcodehash.rs | 6 +- .../src/evm_circuit/execution/extcodesize.rs | 8 +- .../src/evm_circuit/execution/gas.rs | 3 +- .../src/evm_circuit/execution/gasprice.rs | 2 +- .../src/evm_circuit/execution/is_zero.rs | 2 +- .../src/evm_circuit/execution/jump.rs | 2 +- .../src/evm_circuit/execution/jumpi.rs | 3 +- .../src/evm_circuit/execution/logs.rs | 49 ++-- .../src/evm_circuit/execution/memory.rs | 5 +- .../src/evm_circuit/execution/mul_div_mod.rs | 5 +- .../src/evm_circuit/execution/mulmod.rs | 4 +- .../src/evm_circuit/execution/not.rs | 3 +- .../src/evm_circuit/execution/origin.rs | 2 +- .../src/evm_circuit/execution/pc.rs | 2 +- .../src/evm_circuit/execution/pop.rs | 2 +- .../src/evm_circuit/execution/push.rs | 4 +- .../evm_circuit/execution/return_revert.rs | 6 +- .../evm_circuit/execution/returndatacopy.rs | 4 +- .../evm_circuit/execution/returndatasize.rs | 2 +- .../src/evm_circuit/execution/sar.rs | 3 +- .../src/evm_circuit/execution/sdiv_smod.rs | 5 +- .../src/evm_circuit/execution/selfbalance.rs | 2 +- .../src/evm_circuit/execution/sha3.rs | 5 +- .../src/evm_circuit/execution/shl_shr.rs | 5 +- .../execution/signed_comparator.rs | 8 +- .../src/evm_circuit/execution/signextend.rs | 4 +- .../src/evm_circuit/execution/sload.rs | 9 +- .../src/evm_circuit/execution/sstore.rs | 12 +- .../src/evm_circuit/execution/stop.rs | 4 +- .../src/evm_circuit/execution/swap.rs | 4 +- zkevm-circuits/src/evm_circuit/step.rs | 172 ++++++++++++- zkevm-circuits/src/evm_circuit/util.rs | 7 +- .../src/evm_circuit/util/common_gadget.rs | 12 +- zkevm-circuits/src/table.rs | 23 +- zkevm-circuits/src/witness.rs | 3 +- zkevm-circuits/src/witness/block.rs | 21 +- zkevm-circuits/src/witness/rw.rs | 15 +- zkevm-circuits/src/witness/step.rs | 242 ------------------ zkevm-circuits/src/witness/tx.rs | 6 +- 81 files changed, 509 insertions(+), 565 deletions(-) delete mode 100644 zkevm-circuits/src/witness/step.rs diff --git a/bus-mapping/src/circuit_input_builder/execution.rs b/bus-mapping/src/circuit_input_builder/execution.rs index e142d257dc..20b3048682 100644 --- a/bus-mapping/src/circuit_input_builder/execution.rs +++ b/bus-mapping/src/circuit_input_builder/execution.rs @@ -86,6 +86,45 @@ impl ExecStep { Some(ExecError::OutOfGas(_) | ExecError::StackOverflow | ExecError::StackUnderflow) ) } + + /// Try get opcode, if possible + pub fn opcode(&self) -> Option { + match self.exec_state { + ExecState::Op(op) => Some(op), + _ => None, + } + } + + /// get rw index + pub fn rw_index(&self, index: usize) -> OperationRef { + self.bus_mapping_instance[index] + } + + /// Get the size of read and writes + pub fn rw_indices_len(&self) -> usize { + self.bus_mapping_instance.len() + } + + /// Get stack pointer + pub fn stack_pointer(&self) -> u64 { + 1024 - self.stack_size as u64 + } + + /// The memory size in word **before** this step + pub fn memory_word_size(&self) -> u64 { + let n_bytes_word = 32u64; + let memory_size = self.memory_size as u64; + // EVM always pads the memory size to word size + // https://github.com/ethereum/go-ethereum/blob/a340721aa909ea4b541ffd1ea5e9c7bd441ff769/core/vm/interpreter.go#L201-L205 + // Thus, the memory size must be a multiple of 32 bytes. + assert_eq!(memory_size % n_bytes_word, 0); + memory_size / n_bytes_word + } + + /// Get program counter + pub fn program_counter(&self) -> u64 { + self.pc.0.try_into().expect("program counter can fit u64") + } } /// Execution state diff --git a/bus-mapping/src/operation.rs b/bus-mapping/src/operation.rs index 8b39ce7219..cf0df09fda 100644 --- a/bus-mapping/src/operation.rs +++ b/bus-mapping/src/operation.rs @@ -50,6 +50,12 @@ impl From for usize { } } +impl From for u64 { + fn from(addr: RWCounter) -> u64 { + addr.0.try_into().expect("rwc should not overflow") + } +} + impl From for RWCounter { fn from(rwc: usize) -> Self { RWCounter(rwc) diff --git a/eth-types/src/evm_types.rs b/eth-types/src/evm_types.rs index 9837d79251..1dece74eb2 100644 --- a/eth-types/src/evm_types.rs +++ b/eth-types/src/evm_types.rs @@ -54,12 +54,24 @@ impl ProgramCounter { #[derive(Default, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Gas(pub u64); +impl fmt::Display for Gas { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!("{}", self.0)) + } +} + impl fmt::Debug for Gas { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("{}", self.0)) } } +impl From for u64 { + fn from(value: Gas) -> Self { + value.0 + } +} + /// Quotient for max refund of gas used pub const MAX_REFUND_QUOTIENT_OF_GAS_USED: usize = 5; /// Gas stipend when CALL or CALLCODE is attached with value. @@ -69,6 +81,12 @@ pub const GAS_STIPEND_CALL_WITH_VALUE: u64 = 2300; #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Default)] pub struct GasCost(pub u64); +impl fmt::Display for GasCost { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!("{}", self.0)) + } +} + impl fmt::Debug for GasCost { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("{}", self.0)) diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index be8257f021..7cf334e891 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -14,6 +14,7 @@ pub(crate) mod util; #[cfg(any(feature = "test", test))] pub(crate) mod test; +use self::step::HasExecutionState; #[cfg(any(feature = "test", test, feature = "test-circuits"))] pub use self::EvmCircuit as TestEvmCircuit; @@ -222,7 +223,7 @@ impl EvmCircuit { let mut num_rows = 0; for transaction in &block.txs { for step in &transaction.steps { - num_rows += step.execution_state.get_step_height(); + num_rows += step.execution_state().get_step_height(); } } @@ -280,7 +281,7 @@ pub(crate) fn detect_fixed_table_tags(block: &Block) -> Vec ExecutionConfig { if next.is_none() { break; } - let height = step.execution_state.get_step_height(); + let height = step.execution_state().get_step_height(); // Assign the step witness self.assign_exec_step( @@ -1074,8 +1075,8 @@ impl ExecutionConfig { return Ok(()); } assert_eq!(height, 1); - assert!(step.rw_indices.is_empty()); - assert!(matches!(step.execution_state, ExecutionState::EndBlock)); + assert!(step.rw_indices_len() == 0); + assert!(matches!(step.execution_state(), ExecutionState::EndBlock)); // Disable access to next step deliberately for "repeatable" step let region = &mut CachedRegion::<'_, '_, F>::new( @@ -1088,7 +1089,7 @@ impl ExecutionConfig { self.assign_exec_step_int(region, offset_begin, block, transaction, call, step)?; region.replicate_assignment_for_range( - || format!("repeat {:?} rows", step.execution_state), + || format!("repeat {:?} rows", step.execution_state()), offset_begin + 1, offset_end, )?; @@ -1109,11 +1110,11 @@ impl ExecutionConfig { next: Option<(&Transaction, &Call, &ExecStep)>, challenges: &Challenges>, ) -> Result<(), Error> { - if !matches!(step.execution_state, ExecutionState::EndBlock) { + if !matches!(step.execution_state(), ExecutionState::EndBlock) { log::trace!( "assign_exec_step offset: {} state {:?} step: {:?} call: {:?}", offset, - step.execution_state, + step.execution_state(), step, call ); @@ -1165,7 +1166,7 @@ impl ExecutionConfig { }; } - match step.execution_state { + match step.execution_state() { // internal states ExecutionState::BeginTx => assign_exec_step!(self.begin_tx_gadget), ExecutionState::EndTx => assign_exec_step!(self.end_tx_gadget), @@ -1304,7 +1305,7 @@ impl ExecutionConfig { assign_exec_step!(self.error_return_data_out_of_bound) } - _ => evm_unimplemented!("unimplemented ExecutionState: {:?}", step.execution_state), + unimpl_state => evm_unimplemented!("unimplemented ExecutionState: {:?}", unimpl_state), } // Fill in the witness values for stored expressions @@ -1312,8 +1313,8 @@ impl ExecutionConfig { // enable with `RUST_LOG=debug` if log::log_enabled!(log::Level::Debug) { - let is_padding_step = matches!(step.execution_state, ExecutionState::EndBlock) - && step.rw_indices.is_empty(); + let is_padding_step = matches!(step.execution_state(), ExecutionState::EndBlock) + && step.rw_indices_len() == 0; if !is_padding_step { // expensive function call Self::check_rw_lookup( @@ -1337,8 +1338,8 @@ impl ExecutionConfig { let mut assigned_stored_expressions = Vec::new(); for stored_expression in self .stored_expressions_map - .get(&step.execution_state) - .unwrap_or_else(|| panic!("Execution state unknown: {:?}", step.execution_state)) + .get(&step.execution_state()) + .unwrap_or_else(|| panic!("Execution state unknown: {:?}", step.execution_state())) { let assigned = stored_expression.assign(region, offset)?; assigned.map(|v| { @@ -1373,10 +1374,8 @@ impl ExecutionConfig { } } - let rlc_assignments: BTreeSet<_> = step - .rw_indices - .iter() - .map(|rw_idx| block.rws[*rw_idx]) + let rlc_assignments: BTreeSet<_> = (0..step.rw_indices_len()) + .map(|index| block.get_rws(step, index)) .map(|rw| { rw.table_assignment_aux(evm_randomness) .rlc(lookup_randomness) @@ -1396,10 +1395,10 @@ impl ExecutionConfig { // Check that the number of rw operations generated from the bus-mapping // correspond to the number of assigned rw lookups by the EVM Circuit // plus the number of rw lookups done by the copy circuit. - if step.rw_indices.len() != assigned_rw_values.len() + step.copy_rw_counter_delta as usize { + if step.rw_indices_len() != assigned_rw_values.len() + step.copy_rw_counter_delta as usize { log::error!( "step.rw_indices.len: {} != assigned_rw_values.len: {} + step.copy_rw_counter_delta: {} in step: {:?}", - step.rw_indices.len(), + step.rw_indices_len(), assigned_rw_values.len(), step.copy_rw_counter_delta, step @@ -1423,23 +1422,21 @@ impl ExecutionConfig { // corresponding rw lookup, but in the bus-mapping they are // generated at the end of the step. let idx = if is_rev { - step.rw_indices.len() - rev_count + step.rw_indices_len() - rev_count } else { idx - rev_count }; - let rw_idx = step.rw_indices[idx]; - let rw = block.rws[rw_idx]; + let rw = block.get_rws(step, idx); let table_assignments = rw.table_assignment_aux(evm_randomness); let rlc = table_assignments.rlc(lookup_randomness); if rlc != assigned_rw_value.1 { log::error!( - "incorrect rw witness. lookup input name: \"{}\"\nassigned={:?}\nrlc ={:?}\nrw index: {:?}, {}th rw of step {:?}, rw: {:?}", + "incorrect rw witness. lookup input name: \"{}\"\nassigned={:?}\nrlc ={:?}\n{}th rw of step {:?}, rw: {:?}", assigned_rw_value.0, assigned_rw_value.1, rlc, - rw_idx, idx, - step.execution_state, + step.execution_state(), rw); } } diff --git a/zkevm-circuits/src/evm_circuit/execution/add_sub.rs b/zkevm-circuits/src/evm_circuit/execution/add_sub.rs index fb6e457e27..94065d66d8 100644 --- a/zkevm-circuits/src/evm_circuit/execution/add_sub.rs +++ b/zkevm-circuits/src/evm_circuit/execution/add_sub.rs @@ -82,13 +82,13 @@ impl ExecutionGadget for AddSubGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); let indices = if opcode == OpcodeId::SUB { - [step.rw_indices[2], step.rw_indices[1], step.rw_indices[0]] + [2, 1, 0] } else { - [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]] + [0, 1, 2] }; - let [a, b, c] = indices.map(|idx| block.rws[idx].stack_value()); + let [a, b, c] = indices.map(|index| block.get_rws(step, index).stack_value()); self.add_words.assign(region, offset, [a, b], c)?; self.is_sub.assign( region, diff --git a/zkevm-circuits/src/evm_circuit/execution/addmod.rs b/zkevm-circuits/src/evm_circuit/execution/addmod.rs index 51d350c096..5ae1f1b5f5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/addmod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/addmod.rs @@ -150,9 +150,7 @@ impl ExecutionGadget for AddModGadget { self.same_context.assign_exec_step(region, offset, step)?; // get stack values - let [mut r, n, b, a] = [3, 2, 1, 0] - .map(|idx| step.rw_indices[idx]) - .map(|idx| block.rws[idx].stack_value()); + let [mut r, n, b, a] = [3, 2, 1, 0].map(|index| block.get_rws(step, index).stack_value()); // assing a,b & n stack values self.a.assign(region, offset, Some(a.to_le_bytes()))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/address.rs b/zkevm-circuits/src/evm_circuit/execution/address.rs index f663d87e88..13ef41aa42 100644 --- a/zkevm-circuits/src/evm_circuit/execution/address.rs +++ b/zkevm-circuits/src/evm_circuit/execution/address.rs @@ -16,7 +16,6 @@ use crate::{ use bus_mapping::evm::OpcodeId; use eth_types::{Field, ToAddress, ToLittleEndian}; use halo2_proofs::plonk::Error; -use std::convert::TryInto; #[derive(Clone, Debug)] pub(crate) struct AddressGadget { @@ -70,7 +69,7 @@ impl ExecutionGadget for AddressGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let address = block.rws[step.rw_indices[1]].stack_value(); + let address = block.get_rws(step, 1).stack_value(); debug_assert_eq!(call.address, address.to_address()); self.address.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/balance.rs b/zkevm-circuits/src/evm_circuit/execution/balance.rs index fb7606a39a..f392ad2508 100644 --- a/zkevm-circuits/src/evm_circuit/execution/balance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/balance.rs @@ -109,7 +109,7 @@ impl ExecutionGadget for BalanceGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let address = block.rws[step.rw_indices[0]].stack_value(); + let address = block.get_rws(step, 0).stack_value(); self.address_word .assign(region, offset, Some(address.to_le_bytes()))?; @@ -123,11 +123,11 @@ impl ExecutionGadget for BalanceGadget { call.is_persistent, )?; - let (_, is_warm) = block.rws[step.rw_indices[4]].tx_access_list_value_pair(); + let (_, is_warm) = block.get_rws(step, 4).tx_access_list_value_pair(); self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; - let code_hash = block.rws[step.rw_indices[5]].account_value_pair().0; + let code_hash = block.get_rws(step, 5).account_value_pair().0; self.code_hash .assign(region, offset, region.word_rlc(code_hash))?; self.not_exists @@ -135,7 +135,7 @@ impl ExecutionGadget for BalanceGadget { let balance = if code_hash.is_zero() { eth_types::Word::zero() } else { - block.rws[step.rw_indices[6]].account_value_pair().0 + block.get_rws(step, 6).account_value_pair().0 }; self.balance .assign(region, offset, region.word_rlc(balance))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index a7099163d8..230fe1d549 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -511,7 +511,7 @@ impl ExecutionGadget for BeginTxGadget { call.is_persistent, )?; self.sufficient_gas_left - .assign(region, offset, F::from(tx.gas - step.gas_cost))?; + .assign(region, offset, F::from(tx.gas - step.gas_cost.0))?; self.transfer_with_gas_fee.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/execution/bitwise.rs b/zkevm-circuits/src/evm_circuit/execution/bitwise.rs index 90979590fa..eef97570fb 100644 --- a/zkevm-circuits/src/evm_circuit/execution/bitwise.rs +++ b/zkevm-circuits/src/evm_circuit/execution/bitwise.rs @@ -87,8 +87,7 @@ impl ExecutionGadget for BitwiseGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let [a, b, c] = [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]] - .map(|idx| block.rws[idx].stack_value()); + let [a, b, c] = [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); self.a.assign(region, offset, Some(a.to_le_bytes()))?; self.b.assign(region, offset, Some(b.to_le_bytes()))?; self.c.assign(region, offset, Some(c.to_le_bytes()))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs index 31ed3e8a16..f53b0c96b1 100644 --- a/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/block_ctx.rs @@ -90,7 +90,7 @@ impl ExecutionGadget for BlockCtxU64Gadget { .same_context .assign_exec_step(region, offset, step)?; - let value = block.rws[step.rw_indices[0]].stack_value(); + let value = block.get_rws(step, 0).stack_value(); self.value_u64.value.assign( region, @@ -131,7 +131,7 @@ impl ExecutionGadget for BlockCtxU160Gadget { .same_context .assign_exec_step(region, offset, step)?; - let value = block.rws[step.rw_indices[0]].stack_value(); + let value = block.get_rws(step, 0).stack_value(); self.value_u160.value.assign( region, @@ -176,7 +176,7 @@ impl ExecutionGadget for BlockCtxU256Gadget { .same_context .assign_exec_step(region, offset, step)?; - let value = block.rws[step.rw_indices[0]].stack_value(); + let value = block.get_rws(step, 0).stack_value(); self.value_u256 .value diff --git a/zkevm-circuits/src/evm_circuit/execution/blockhash.rs b/zkevm-circuits/src/evm_circuit/execution/blockhash.rs index 9487951323..78d140494f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/blockhash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/blockhash.rs @@ -109,7 +109,7 @@ impl ExecutionGadget for BlockHashGadget { .to_scalar() .expect("unexpected U256 -> Scalar conversion failure"); - let block_number = block.rws[step.rw_indices[0]].stack_value(); + let block_number = block.get_rws(step, 0).stack_value(); self.block_number .assign(region, offset, block_number, current_block_number)?; @@ -119,7 +119,7 @@ impl ExecutionGadget for BlockHashGadget { self.block_hash.assign( region, offset, - Some(block.rws[step.rw_indices[1]].stack_value().to_le_bytes()), + Some(block.get_rws(step, 1).stack_value().to_le_bytes()), )?; self.diff_lt.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/byte.rs b/zkevm-circuits/src/evm_circuit/execution/byte.rs index dd4b4317d7..a21c0570e8 100644 --- a/zkevm-circuits/src/evm_circuit/execution/byte.rs +++ b/zkevm-circuits/src/evm_circuit/execution/byte.rs @@ -101,8 +101,8 @@ impl ExecutionGadget for ByteGadget { self.same_context.assign_exec_step(region, offset, step)?; // Inputs/Outputs - let index = block.rws[step.rw_indices[0]].stack_value().to_le_bytes(); - let value = block.rws[step.rw_indices[1]].stack_value().to_le_bytes(); + let index = block.get_rws(step, 0).stack_value().to_le_bytes(); + let value = block.get_rws(step, 1).stack_value().to_le_bytes(); self.index.assign(region, offset, Some(index))?; self.value.assign(region, offset, Some(value))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index 216cfb15d9..219941902b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -179,8 +179,7 @@ impl ExecutionGadget for CallDataCopyGadget { self.same_context.assign_exec_step(region, offset, step)?; let [memory_offset, data_offset, length] = - [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]] - .map(|idx| block.rws[idx].stack_value()); + [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); let memory_address = self .memory_address .assign(region, offset, memory_offset, length)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs index f443980188..555a105667 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs @@ -226,7 +226,7 @@ impl ExecutionGadget for CallDataLoadGadget { self.call_data_offset .assign(region, offset, Value::known(F::from(call_data_offset)))?; - let data_offset = block.rws[step.rw_indices[0]].stack_value(); + let data_offset = block.get_rws(step, 0).stack_value(); let offset_not_overflow = self.data_offset .assign(region, offset, data_offset, F::from(call_data_length))?; @@ -253,8 +253,9 @@ impl ExecutionGadget for CallDataLoadGadget { } else { // Fetch from memory. if src_addr + (i as u64) < call.call_data_offset + call.call_data_length { - *byte = - block.rws[step.rw_indices[OFFSET_RW_MEMORY_INDICES + i]].memory_value(); + *byte = block + .get_rws(step, OFFSET_RW_MEMORY_INDICES + i) + .memory_value(); } } } diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs index e9485a61eb..dc6028e53b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatasize.rs @@ -70,7 +70,7 @@ impl ExecutionGadget for CallDataSizeGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let call_data_size = block.rws[step.rw_indices[1]].stack_value(); + let call_data_size = block.get_rws(step, 1).stack_value(); self.call_data_size.assign( region, diff --git a/zkevm-circuits/src/evm_circuit/execution/caller.rs b/zkevm-circuits/src/evm_circuit/execution/caller.rs index 19bc8f79ae..a57b97dc8e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/caller.rs +++ b/zkevm-circuits/src/evm_circuit/execution/caller.rs @@ -71,7 +71,7 @@ impl ExecutionGadget for CallerGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let caller = block.rws[step.rw_indices[1]].stack_value(); + let caller = block.get_rws(step, 1).stack_value(); self.caller_address.assign( region, diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index cdd1874a69..de36e6462a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -440,22 +440,15 @@ impl ExecutionGadget for CallOpGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); let is_call = opcode == OpcodeId::CALL; let is_callcode = opcode == OpcodeId::CALLCODE; let is_delegatecall = opcode == OpcodeId::DELEGATECALL; - let [tx_id, is_static, depth, current_callee_address] = [ - step.rw_indices[0], - step.rw_indices[3], - step.rw_indices[4], - step.rw_indices[5], - ] - .map(|idx| block.rws[idx].call_context_value()); + let [tx_id, is_static, depth, current_callee_address] = + [0, 3, 4, 5].map(|index| block.get_rws(step, index).call_context_value()); let is_error_depth = depth.low_u64() > 1024; self.is_depth_ok .assign(region, offset, F::from(depth.low_u64()), F::from(1025))?; - let stack_index = 6; - // This offset is used to change the index offset of `step.rw_indices`. // Since both CALL and CALLCODE have an extra stack pop `value`, and // opcode DELEGATECALL has two extra call context lookups - current @@ -463,46 +456,34 @@ impl ExecutionGadget for CallOpGadget { let mut rw_offset = 0; let [current_caller_address, current_value] = if is_delegatecall { rw_offset += 2; - [step.rw_indices[6], step.rw_indices[7]].map(|idx| block.rws[idx].call_context_value()) + [6, 7].map(|index| block.get_rws(step, index).call_context_value()) } else { [U256::zero(), U256::zero()] }; - let [gas, callee_address] = [ - step.rw_indices[stack_index + rw_offset], - step.rw_indices[stack_index + 1 + rw_offset], - ] - .map(|idx| block.rws[idx].stack_value()); + let [gas, callee_address] = + [6, 7].map(|i| block.get_rws(step, i + rw_offset).stack_value()); let value = if is_call || is_callcode { + let value = block.get_rws(step, 8 + rw_offset).stack_value(); rw_offset += 1; - block.rws[step.rw_indices[7 + rw_offset]].stack_value() + value } else { U256::zero() }; - let [cd_offset, cd_length, rd_offset, rd_length, is_success] = [ - step.rw_indices[stack_index + 2 + rw_offset], - step.rw_indices[stack_index + 3 + rw_offset], - step.rw_indices[stack_index + 4 + rw_offset], - step.rw_indices[stack_index + 5 + rw_offset], - step.rw_indices[stack_index + 6 + rw_offset], - ] - .map(|idx| block.rws[idx].stack_value()); - let callee_code_hash = block.rws[step.rw_indices[13 + rw_offset]] - .account_value_pair() - .0; + let [cd_offset, cd_length, rd_offset, rd_length, is_success] = + [8, 9, 10, 11, 12].map(|i| block.get_rws(step, i + rw_offset).stack_value()); + let callee_code_hash = block.get_rws(step, 13 + rw_offset).account_value_pair().0; let callee_exists = !callee_code_hash.is_zero(); - let (is_warm, is_warm_prev) = - block.rws[step.rw_indices[14 + rw_offset]].tx_access_list_value_pair(); + let (is_warm, is_warm_prev) = block + .get_rws(step, 14 + rw_offset) + .tx_access_list_value_pair(); - let [callee_rw_counter_end_of_reversion, callee_is_persistent] = [ - step.rw_indices[15 + rw_offset], - step.rw_indices[16 + rw_offset], - ] - .map(|idx| block.rws[idx].call_context_value()); + let [callee_rw_counter_end_of_reversion, callee_is_persistent] = + [15, 16].map(|index| block.get_rws(step, index + rw_offset).call_context_value()); // check if it is insufficient balance case. // get caller balance - let (caller_balance, _) = block.rws[step.rw_indices[17 + rw_offset]].account_value_pair(); + let (caller_balance, _) = block.get_rws(step, 17 + rw_offset).account_value_pair(); self.caller_balance_word .assign(region, offset, Some(caller_balance.to_le_bytes()))?; self.is_insufficient_balance @@ -510,15 +491,11 @@ impl ExecutionGadget for CallOpGadget { let is_insufficient = (value > caller_balance) && (is_call || is_callcode); // only call opcode do transfer in sucessful case. - let (caller_balance_pair, callee_balance_pair) = + let [caller_balance_pair, callee_balance_pair] = if is_call && !is_insufficient && !is_error_depth && !value.is_zero() { - rw_offset += 2; - ( - block.rws[step.rw_indices[16 + rw_offset]].account_value_pair(), - block.rws[step.rw_indices[17 + rw_offset]].account_value_pair(), - ) + [18, 19].map(|index| block.get_rws(step, index + rw_offset).account_value_pair()) } else { - ((U256::zero(), U256::zero()), (U256::zero(), U256::zero())) + [(U256::zero(), U256::zero()), (U256::zero(), U256::zero())] }; self.opcode @@ -619,7 +596,7 @@ impl ExecutionGadget for CallOpGadget { has_value, !callee_exists, )?; - let gas_available = step.gas_left - gas_cost; + let gas_available: u64 = step.gas_left.0 - gas_cost; self.one_64th_gas .assign(region, offset, gas_available.into())?; diff --git a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs index 12a9e95f2c..237c954096 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callvalue.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callvalue.rs @@ -71,7 +71,7 @@ impl ExecutionGadget for CallValueGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let call_value = block.rws[step.rw_indices[1]].stack_value(); + let call_value = block.get_rws(step, 1).stack_value(); self.call_value .assign(region, offset, region.word_rlc(call_value))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/chainid.rs b/zkevm-circuits/src/evm_circuit/execution/chainid.rs index 6f6146e626..e635b1e391 100644 --- a/zkevm-circuits/src/evm_circuit/execution/chainid.rs +++ b/zkevm-circuits/src/evm_circuit/execution/chainid.rs @@ -63,7 +63,7 @@ impl ExecutionGadget for ChainIdGadget { step: &ExecStep, ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let chain_id = block.rws[step.rw_indices[0]].stack_value(); + let chain_id = block.get_rws(step, 0).stack_value(); self.chain_id .assign(region, offset, region.word_rlc(chain_id))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index c4b0642609..020a88fedf 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -152,7 +152,7 @@ impl ExecutionGadget for CodeCopyGadget { // 3. `size` is the number of // bytes to be read and written (0s to be copied for out of bounds). let [dest_offset, code_offset, size] = - [0, 1, 2].map(|i| block.rws[step.rw_indices[i]].stack_value()); + [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); let bytecode = block .bytecodes diff --git a/zkevm-circuits/src/evm_circuit/execution/codesize.rs b/zkevm-circuits/src/evm_circuit/execution/codesize.rs index bd98f3ea76..86df028c24 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codesize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codesize.rs @@ -76,7 +76,7 @@ impl ExecutionGadget for CodesizeGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let codesize = block.rws[step.rw_indices[0]].stack_value().as_u64(); + let codesize = block.get_rws(step, 0).stack_value().as_u64(); for (c, b) in self .codesize_bytes diff --git a/zkevm-circuits/src/evm_circuit/execution/comparator.rs b/zkevm-circuits/src/evm_circuit/execution/comparator.rs index e22fbf4864..9d593ef747 100644 --- a/zkevm-circuits/src/evm_circuit/execution/comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/comparator.rs @@ -115,7 +115,7 @@ impl ExecutionGadget for ComparatorGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); // EQ op check self.is_eq.assign( @@ -133,13 +133,9 @@ impl ExecutionGadget for ComparatorGadget { F::from(OpcodeId::GT.as_u8() as u64), )?; - let indices = if is_gt == F::ONE { - [step.rw_indices[1], step.rw_indices[0]] - } else { - [step.rw_indices[0], step.rw_indices[1]] - }; - let [a, b] = indices.map(|idx| block.rws[idx].stack_value().to_le_bytes()); - let result = block.rws[step.rw_indices[2]].stack_value(); + let indices = if is_gt == F::ONE { [1, 0] } else { [0, 1] }; + let [a, b] = indices.map(|index| block.get_rws(step, index).stack_value().to_le_bytes()); + let result = block.get_rws(step, 2).stack_value(); // `a[0..16] <= b[0..16]` self.comparison_lo.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/dummy.rs b/zkevm-circuits/src/evm_circuit/execution/dummy.rs index 693b533baf..eda17c468d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/dummy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/dummy.rs @@ -55,16 +55,16 @@ impl // process of being implemented but are still // using DummyGadget. // See `bus-mapping/src/evm/opcodes.rs` - if step.rw_indices.len() != N_POP + N_PUSH { + if step.rw_indices_len() != N_POP + N_PUSH { log::warn!("DummyGadget: wrong number of rw indices for {:?}", step); } for i in 0..N_POP { - let value = block.rws[step.rw_indices[i]].stack_value(); + let value = block.get_rws(step, i).stack_value(); self.pops[i].assign(region, offset, Some(value.to_le_bytes()))?; } for i in 0..N_PUSH { - let value = block.rws[step.rw_indices[N_POP + i]].stack_value(); + let value = block.get_rws(step, N_POP + i).stack_value(); self.pushes[i].assign(region, offset, Some(value.to_le_bytes()))?; } Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/execution/dup.rs b/zkevm-circuits/src/evm_circuit/execution/dup.rs index 51c808b978..9dc0816dd7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/dup.rs +++ b/zkevm-circuits/src/evm_circuit/execution/dup.rs @@ -65,7 +65,7 @@ impl ExecutionGadget for DupGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let value = block.rws[step.rw_indices[0]].stack_value(); + let value = block.get_rws(step, 0).stack_value(); self.value.assign(region, offset, region.word_rlc(value))?; Ok(()) diff --git a/zkevm-circuits/src/evm_circuit/execution/end_block.rs b/zkevm-circuits/src/evm_circuit/execution/end_block.rs index ed07de8da2..0b3eaee2a4 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_block.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_block.rs @@ -120,7 +120,7 @@ impl ExecutionGadget for EndBlockGadget { step: &ExecStep, ) -> Result<(), Error> { self.is_empty_block - .assign(region, offset, F::from(step.rw_counter as u64 - 1))?; + .assign(region, offset, F::from(u64::from(step.rwc) - 1))?; let max_rws = F::from(block.circuits_params.max_rws as u64); let max_rws_assigned = self.max_rws.assign(region, offset, Value::known(max_rws))?; @@ -133,7 +133,7 @@ impl ExecutionGadget for EndBlockGadget { let max_txs_assigned = self.max_txs.assign(region, offset, Value::known(max_txs))?; // When rw_indices is not empty, we're at the last row (at a fixed offset), // where we need to access the max_rws and max_txs constant. - if !step.rw_indices.is_empty() { + if !step.rw_indices_len() == 0 { region.constrain_constant(max_rws_assigned, max_rws)?; region.constrain_constant(max_txs_assigned, max_txs)?; } diff --git a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs index 9261a6801d..9fdddd7c2b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -202,10 +202,10 @@ impl ExecutionGadget for EndTxGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let gas_used = tx.gas - step.gas_left; - let (refund, _) = block.rws[step.rw_indices[2]].tx_refund_value_pair(); + let gas_used = tx.gas - step.gas_left.0; + let (refund, _) = block.get_rws(step, 2).tx_refund_value_pair(); let [(caller_balance, caller_balance_prev), (coinbase_balance, coinbase_balance_prev)] = - [step.rw_indices[3], step.rw_indices[4]].map(|idx| block.rws[idx].account_value_pair()); + [3, 4].map(|index| block.get_rws(step, index).account_value_pair()); self.tx_id .assign(region, offset, Value::known(F::from(tx.id as u64)))?; @@ -221,12 +221,12 @@ impl ExecutionGadget for EndTxGadget { F::from(refund), )?; let effective_refund = refund.min(max_refund as u64); - let gas_fee_refund = tx.gas_price * (effective_refund + step.gas_left); + let gas_fee_refund = tx.gas_price * (effective_refund + step.gas_left.0); self.mul_gas_price_by_refund.assign( region, offset, tx.gas_price, - effective_refund + step.gas_left, + effective_refund + step.gas_left.0, gas_fee_refund, )?; self.tx_caller_address.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index 72e0767dd8..44d0642f29 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -112,13 +112,13 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); let is_jumpi = opcode == OpcodeId::JUMPI; self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; let condition = if is_jumpi { - block.rws[step.rw_indices[1]].stack_value() + block.get_rws(step, 1).stack_value() } else { U256::zero() }; @@ -132,7 +132,7 @@ impl ExecutionGadget for ErrorInvalidJumpGadget { self.code_len .assign(region, offset, Value::known(F::from(code_len)))?; - let dest = block.rws[step.rw_indices[0]].stack_value(); + let dest = block.get_rws(step, 0).stack_value(); self.dest.assign(region, offset, dest, F::from(code_len))?; // set default value in case can not find value, is_code from bytecode table diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs index 41b4e69026..868a830306 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs @@ -56,7 +56,7 @@ impl ExecutionGadget for ErrorInvalidOpcodeGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = F::from(step.opcode.unwrap().as_u64()); + let opcode = F::from(step.opcode().unwrap().as_u64()); self.opcode.assign(region, offset, Value::known(opcode))?; self.common_error_gadget diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs index ce257fbbea..07884165b9 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs @@ -120,37 +120,29 @@ impl ExecutionGadget for ErrorOOGCallGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); let is_call_or_callcode = usize::from([OpcodeId::CALL, OpcodeId::CALLCODE].contains(&opcode)); let [tx_id, is_static] = - [step.rw_indices[0], step.rw_indices[1]].map(|idx| block.rws[idx].call_context_value()); - let stack_index = 2; - let [gas, callee_address] = [ - step.rw_indices[stack_index], - step.rw_indices[stack_index + 1], - ] - .map(|idx| block.rws[idx].stack_value()); + [0, 1].map(|index| block.get_rws(step, index).call_context_value()); + let [gas, callee_address] = [2, 3].map(|index| block.get_rws(step, index).stack_value()); let value = if is_call_or_callcode == 1 { - block.rws[step.rw_indices[stack_index + 2]].stack_value() + block.get_rws(step, 4).stack_value() } else { U256::zero() }; - let [cd_offset, cd_length, rd_offset, rd_length] = [ - step.rw_indices[stack_index + is_call_or_callcode + 2], - step.rw_indices[stack_index + is_call_or_callcode + 3], - step.rw_indices[stack_index + is_call_or_callcode + 4], - step.rw_indices[stack_index + is_call_or_callcode + 5], - ] - .map(|idx| block.rws[idx].stack_value()); - - let callee_code_hash = block.rws[step.rw_indices[9 + is_call_or_callcode]] + let [cd_offset, cd_length, rd_offset, rd_length] = + [4, 5, 6, 7].map(|i| block.get_rws(step, is_call_or_callcode + i).stack_value()); + + let callee_code_hash = block + .get_rws(step, 9 + is_call_or_callcode) .account_value_pair() .0; let callee_exists = !callee_code_hash.is_zero(); - let (is_warm, is_warm_prev) = - block.rws[step.rw_indices[10 + is_call_or_callcode]].tx_access_list_value_pair(); + let (is_warm, is_warm_prev) = block + .get_rws(step, 10 + is_call_or_callcode) + .tx_access_list_value_pair(); let memory_expansion_gas_cost = self.call.assign( region, @@ -212,7 +204,7 @@ impl ExecutionGadget for ErrorOOGCallGadget { self.insufficient_gas.assign_value( region, offset, - Value::known(F::from(step.gas_left)), + Value::known(F::from(step.gas_left.0)), Value::known(F::from(gas_cost)), )?; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs index e13d874b9b..0dff4423ec 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs @@ -65,20 +65,20 @@ impl ExecutionGadget for ErrorOOGConstantGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; // Inputs/Outputs self.gas_required - .assign(region, offset, Value::known(F::from(step.gas_cost)))?; + .assign(region, offset, Value::known(F::from(step.gas_cost.0)))?; // Gas insufficient check // Get `gas_available` variable here once it's available self.insufficient_gas.assign( region, offset, - F::from(step.gas_left), - F::from(step.gas_cost), + F::from(step.gas_left.0), + F::from(step.gas_cost.0), )?; self.common_error_gadget diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs index ed6da019aa..d41edd9ff3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs @@ -97,8 +97,8 @@ impl ExecutionGadget for ErrorOOGExpGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); - let [base, exponent] = [0, 1].map(|idx| block.rws[step.rw_indices[idx]].stack_value()); + let opcode = step.opcode().unwrap(); + let [base, exponent] = [0, 1].map(|index| block.get_rws(step, index).stack_value()); log::debug!( "ErrorOutOfGasEXP: gas_left = {}, gas_cost = {}", @@ -115,8 +115,8 @@ impl ExecutionGadget for ErrorOOGExpGadget { self.insufficient_gas_cost.assign_value( region, offset, - Value::known(F::from(step.gas_left)), - Value::known(F::from(step.gas_cost)), + Value::known(F::from(step.gas_left.0)), + Value::known(F::from(step.gas_cost.0)), )?; self.common_error_gadget .assign(region, offset, block, call, step, 4)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs index 075088eb09..daa2dda87c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs @@ -103,12 +103,11 @@ impl ExecutionGadget for ErrorOOGLogGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; - let [memory_start, msize] = - [step.rw_indices[0], step.rw_indices[1]].map(|idx| block.rws[idx].stack_value()); + let [memory_start, msize] = [0, 1].map(|index| block.get_rws(step, index).stack_value()); let memory_address = self .memory_address @@ -130,8 +129,8 @@ impl ExecutionGadget for ErrorOOGLogGadget { self.insufficient_gas.assign( region, offset, - F::from(step.gas_left), - F::from(step.gas_cost), + F::from(step.gas_left.0), + F::from(step.gas_cost.0), )?; self.common_error_gadget .assign(region, offset, block, call, step, 5)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs index b9511f0000..84089b95e8 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs @@ -155,7 +155,7 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); let is_extcodecopy = opcode == OpcodeId::EXTCODECOPY; log::debug!( @@ -167,8 +167,8 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { let (is_warm, external_address) = if is_extcodecopy { ( - block.rws[step.rw_indices[1]].tx_access_list_value_pair().0, - block.rws[step.rw_indices[2]].stack_value(), + block.get_rws(step, 1).tx_access_list_value_pair().0, + block.get_rws(step, 2).stack_value(), ) } else { (false, U256::zero()) @@ -176,7 +176,7 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { let rw_offset = if is_extcodecopy { 3 } else { 0 }; let [dst_offset, src_offset, copy_size] = [rw_offset, rw_offset + 1, rw_offset + 2] - .map(|idx| block.rws[step.rw_indices[idx]].stack_value()); + .map(|index| block.get_rws(step, index).stack_value()); self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; @@ -212,7 +212,7 @@ impl ExecutionGadget for ErrorOOGMemoryCopyGadget { self.insufficient_gas.assign_value( region, offset, - Value::known(F::from(step.gas_left)), + Value::known(F::from(step.gas_left.into())), Value::known(F::from(constant_gas_cost.0 + memory_copier_gas)), )?; self.is_extcodecopy.assign( diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs index ac00733760..9b350fd79c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs @@ -159,15 +159,14 @@ impl ExecutionGadget for ErrorOOGSloadSstoreGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); let is_sstore = opcode == OpcodeId::SSTORE; - let key = block.rws[step.rw_indices[3]].stack_value(); - let (is_warm, _) = block.rws[step.rw_indices[4]].tx_access_list_value_pair(); + let key = block.get_rws(step, 3).stack_value(); + let (is_warm, _) = block.get_rws(step, 4).tx_access_list_value_pair(); let (value, value_prev, original_value, gas_cost) = if is_sstore { - let value = block.rws[step.rw_indices[5]].stack_value(); - let (_, value_prev, _, original_value) = - block.rws[step.rw_indices[6]].storage_value_aux(); + let value = block.get_rws(step, 5).stack_value(); + let (_, value_prev, _, original_value) = block.get_rws(step, 6).storage_value_aux(); let gas_cost = cal_sstore_gas_cost_for_assignment(value, value_prev, original_value, is_warm); (value, value_prev, original_value, gas_cost) @@ -179,7 +178,7 @@ impl ExecutionGadget for ErrorOOGSloadSstoreGadget { log::debug!( "ErrorOutOfGasSloadSstore: is_sstore = {}, gas_left = {}, gas_cost = {}, gas_sentry = {}", is_sstore, - step.gas_left, + step.gas_left.0, gas_cost, if is_sstore { GasCost::SSTORE_SENTRY.0 } else { 0 }, ); @@ -222,13 +221,13 @@ impl ExecutionGadget for ErrorOOGSloadSstoreGadget { self.insufficient_gas_cost.assign_value( region, offset, - Value::known(F::from(step.gas_left)), + Value::known(F::from(step.gas_left.into())), Value::known(F::from(gas_cost)), )?; self.insufficient_gas_sentry.assign_value( region, offset, - Value::known(F::from(step.gas_left)), + Value::known(F::from(step.gas_left.into())), Value::known(F::from(GasCost::SSTORE_SENTRY.0.checked_add(1).unwrap())), )?; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs index 65f901ede5..9c51ee7357 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_static_memory.rs @@ -95,10 +95,10 @@ impl ExecutionGadget for ErrorOOGStaticMemoryGadget { _: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); // Inputs/Outputs - let address = block.rws[step.rw_indices[0]].stack_value(); + let address = block.get_rws(step, 0).stack_value(); self.address .assign(region, offset, Some(address.to_le_bytes()))?; @@ -131,7 +131,7 @@ impl ExecutionGadget for ErrorOOGStaticMemoryGadget { // Gas insufficient check // Get `gas_available` variable here once it's available self.insufficient_gas - .assign(region, offset, F::from(step.gas_cost - step.gas_left))?; + .assign(region, offset, F::from(step.gas_cost.0 - step.gas_left.0))?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs b/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs index e5c106da5b..5363dd2125 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs @@ -123,13 +123,13 @@ impl ExecutionGadget for ErrorReturnDataOutOfBoundGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; let [dest_offset, data_offset, size] = - [0, 1, 2].map(|i| block.rws[step.rw_indices[i as usize]].stack_value()); + [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); self.memory_offset .assign(region, offset, Value::known(F::from(dest_offset.as_u64())))?; @@ -138,7 +138,7 @@ impl ExecutionGadget for ErrorReturnDataOutOfBoundGadget { self.sum .assign(region, offset, [data_offset, size], remainder_end)?; - let return_data_length = block.rws[step.rw_indices[3]].call_context_value(); + let return_data_length = block.get_rws(step, 3).call_context_value(); self.return_data_length.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs index e7b255c7ef..bb0d1d5967 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs @@ -57,7 +57,7 @@ impl ExecutionGadget for ErrorStackGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs index 28c7416084..83b168c05b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs @@ -100,7 +100,7 @@ impl ExecutionGadget for ErrorWriteProtectionGadget { call: &Call, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); let is_call = opcode == OpcodeId::CALL; self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; @@ -108,8 +108,7 @@ impl ExecutionGadget for ErrorWriteProtectionGadget { if is_call { [gas, code_address, value] = - [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]] - .map(|idx| block.rws[idx].stack_value()); + [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); } self.gas.assign(region, offset, Some(gas.to_le_bytes()))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/exp.rs b/zkevm-circuits/src/evm_circuit/execution/exp.rs index 6e4fe08250..2d7604fc98 100644 --- a/zkevm-circuits/src/evm_circuit/execution/exp.rs +++ b/zkevm-circuits/src/evm_circuit/execution/exp.rs @@ -227,8 +227,7 @@ impl ExecutionGadget for ExponentiationGadget { self.same_context.assign_exec_step(region, offset, step)?; let [base, exponent, exponentiation] = - [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]] - .map(|idx| block.rws[idx].stack_value()); + [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); self.base.assign(region, offset, Some(base.to_le_bytes()))?; self.exponent diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index 376f0f64b7..5bc7f6d307 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -167,7 +167,7 @@ impl ExecutionGadget for ExtcodecopyGadget { self.same_context.assign_exec_step(region, offset, step)?; let [external_address, memory_offset, code_offset, memory_length] = - [0, 1, 2, 3].map(|idx| block.rws[step.rw_indices[idx]].stack_value()); + [0, 1, 2, 3].map(|idx| block.get_rws(step, idx).stack_value()); self.external_address_word .assign(region, offset, Some(external_address.to_le_bytes()))?; let memory_address = @@ -183,11 +183,11 @@ impl ExecutionGadget for ExtcodecopyGadget { call.is_persistent, )?; - let (_, is_warm) = block.rws[step.rw_indices[7]].tx_access_list_value_pair(); + let (_, is_warm) = block.get_rws(step, 7).tx_access_list_value_pair(); self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; - let code_hash = block.rws[step.rw_indices[8]].account_value_pair().0; + let code_hash = block.get_rws(step, 8).account_value_pair().0; self.code_hash .assign(region, offset, region.word_rlc(code_hash))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs index 0d4b0ddd59..a30ba0dad3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs @@ -93,7 +93,7 @@ impl ExecutionGadget for ExtcodehashGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let address = block.rws[step.rw_indices[0]].stack_value(); + let address = block.get_rws(step, 0).stack_value(); self.address_word .assign(region, offset, Some(address.to_le_bytes()))?; @@ -106,11 +106,11 @@ impl ExecutionGadget for ExtcodehashGadget { call.is_persistent, )?; - let (_, is_warm) = block.rws[step.rw_indices[4]].tx_access_list_value_pair(); + let (_, is_warm) = block.get_rws(step, 4).tx_access_list_value_pair(); self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; - let code_hash = block.rws[step.rw_indices[5]].account_value_pair().0; + let code_hash = block.get_rws(step, 5).account_value_pair().0; self.code_hash .assign(region, offset, region.word_rlc(code_hash))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs index bd635a7018..8c00bd63c7 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodesize.rs @@ -111,7 +111,7 @@ impl ExecutionGadget for ExtcodesizeGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let address = block.rws[step.rw_indices[0]].stack_value(); + let address = block.get_rws(step, 0).stack_value(); self.address_word .assign(region, offset, Some(address.to_le_bytes()))?; @@ -125,17 +125,17 @@ impl ExecutionGadget for ExtcodesizeGadget { call.is_persistent, )?; - let (_, is_warm) = block.rws[step.rw_indices[4]].tx_access_list_value_pair(); + let (_, is_warm) = block.get_rws(step, 4).tx_access_list_value_pair(); self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; - let code_hash = block.rws[step.rw_indices[5]].account_value_pair().0; + let code_hash = block.get_rws(step, 5).account_value_pair().0; self.code_hash .assign(region, offset, region.word_rlc(code_hash))?; self.not_exists .assign_value(region, offset, region.word_rlc(code_hash))?; - let code_size = block.rws[step.rw_indices[6]].stack_value().as_u64(); + let code_size = block.get_rws(step, 6).stack_value().as_u64(); self.code_size .assign(region, offset, Some(code_size.to_le_bytes()))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/gas.rs b/zkevm-circuits/src/evm_circuit/execution/gas.rs index 4c9cb5dcd7..57f478191b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gas.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gas.rs @@ -78,6 +78,7 @@ impl ExecutionGadget for GasGadget { offset, Some( step.gas_left + .0 .saturating_sub(OpcodeId::GAS.constant_gas_cost().as_u64()) .to_le_bytes(), ), @@ -146,7 +147,7 @@ mod test { // the circuit verification fails for this scenario. assert_eq!(block.txs.len(), 1); assert_eq!(block.txs[0].steps.len(), 4); - block.txs[0].steps[2].gas_left -= 1; + block.txs[0].steps[2].gas_left.0 -= 1; })) .evm_checks(Box::new(|prover, gate_rows, lookup_rows| { assert!(prover diff --git a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs index ed4c749d90..2e6c5561cb 100644 --- a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs +++ b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs @@ -72,7 +72,7 @@ impl ExecutionGadget for GasPriceGadget { _: &Call, step: &ExecStep, ) -> Result<(), Error> { - let gas_price = block.rws[step.rw_indices[1]].stack_value(); + let gas_price = block.get_rws(step, 1).stack_value(); self.tx_id .assign(region, offset, Value::known(F::from(tx.id as u64)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/is_zero.rs b/zkevm-circuits/src/evm_circuit/execution/is_zero.rs index a0d5e12520..36671e5f5a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/is_zero.rs +++ b/zkevm-circuits/src/evm_circuit/execution/is_zero.rs @@ -64,7 +64,7 @@ impl ExecutionGadget for IsZeroGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let value = block.rws[step.rw_indices[0]].stack_value(); + let value = block.get_rws(step, 0).stack_value(); let value = region.word_rlc(value); self.value.assign(region, offset, value)?; self.is_zero.assign_value(region, offset, value)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/jump.rs b/zkevm-circuits/src/evm_circuit/execution/jump.rs index ead6133a5d..fc03df544b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jump.rs @@ -70,7 +70,7 @@ impl ExecutionGadget for JumpGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let destination = block.rws[step.rw_indices[0]].stack_value(); + let destination = block.get_rws(step, 0).stack_value(); self.destination.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs index 4a463bfd5a..8c131e21e5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/jumpi.rs +++ b/zkevm-circuits/src/evm_circuit/execution/jumpi.rs @@ -93,8 +93,7 @@ impl ExecutionGadget for JumpiGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let [destination, condition] = - [step.rw_indices[0], step.rw_indices[1]].map(|idx| block.rws[idx].stack_value()); + let [destination, condition] = [0, 1].map(|index| block.get_rws(step, index).stack_value()); let condition = region.word_rlc(condition); self.dest.assign(region, offset, destination)?; diff --git a/zkevm-circuits/src/evm_circuit/execution/logs.rs b/zkevm-circuits/src/evm_circuit/execution/logs.rs index 68fb0aed34..e711a01b65 100644 --- a/zkevm-circuits/src/evm_circuit/execution/logs.rs +++ b/zkevm-circuits/src/evm_circuit/execution/logs.rs @@ -14,7 +14,7 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, - table::{CallContextFieldTag, RwTableTag, TxLogFieldTag}, + table::{CallContextFieldTag, TxLogFieldTag}, util::{build_tx_log_expression, Expr}, }; use array_init::array_init; @@ -194,9 +194,7 @@ impl ExecutionGadget for LogGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let [memory_start, msize] = - [step.rw_indices[0], step.rw_indices[1]].map(|idx| block.rws[idx].stack_value()); - + let [memory_start, msize] = [0, 1].map(|index| block.get_rws(step, index).stack_value()); let memory_address = self .memory_address .assign(region, offset, memory_start, msize)?; @@ -205,28 +203,33 @@ impl ExecutionGadget for LogGadget { self.memory_expansion .assign(region, offset, step.memory_word_size(), [memory_address])?; - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); let topic_count = opcode.postfix().expect("opcode with postfix") as usize; assert!(topic_count <= 4); - let is_persistent = call.is_persistent as u64; - let mut topic_stack_entry = if topic_count > 0 { - step.rw_indices[6 + call.is_persistent as usize] - } else { - // if topic_count == 0, this value will be no used anymore - (RwTableTag::Stack, 0usize) - }; - + let is_persistent = call.is_persistent as usize; + let mut topics = (0..topic_count).map(|topic| { + // We compute the index of the correct read-write record from + // bus-mapping/src/evm/opcodes/logs.rs::gen_log_step + // It takes 6 + is_persistent reads or writes to reach the topic stack write section. + // Each topic takes at least 1 stack read. They take an additional tx log write if the + // call is persistent. + block + .get_rws(step, 6 + is_persistent + topic * (1 + is_persistent)) + .stack_value() + }); for i in 0..4 { - let mut topic = region.word_rlc(U256::zero()); - if i < topic_count { - topic = region.word_rlc(block.rws[topic_stack_entry].stack_value()); - self.topic_selectors[i].assign(region, offset, Value::known(F::ONE))?; - topic_stack_entry.1 += 1; - } else { - self.topic_selectors[i].assign(region, offset, Value::known(F::ZERO))?; - } - self.phase2_topics[i].assign(region, offset, topic)?; + let topic = topics.next(); + self.topic_selectors[i].assign( + region, + offset, + Value::known(F::from(topic.is_some().into())), + )?; + self.phase2_topics[i].assign( + region, + offset, + region.word_rlc(topic.unwrap_or_default()), + )?; } self.contract_address.assign( @@ -238,7 +241,7 @@ impl ExecutionGadget for LogGadget { .expect("unexpected Address -> Scalar conversion failure"), ), )?; - + let is_persistent = call.is_persistent as u64; self.is_static_call .assign(region, offset, Value::known(F::from(call.is_static as u64)))?; self.is_persistent diff --git a/zkevm-circuits/src/evm_circuit/execution/memory.rs b/zkevm-circuits/src/evm_circuit/execution/memory.rs index 0ec073b23a..8292f0d4fc 100644 --- a/zkevm-circuits/src/evm_circuit/execution/memory.rs +++ b/zkevm-circuits/src/evm_circuit/execution/memory.rs @@ -128,11 +128,10 @@ impl ExecutionGadget for MemoryGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); // Inputs/Outputs - let [address, value] = - [step.rw_indices[0], step.rw_indices[1]].map(|idx| block.rws[idx].stack_value()); + let [address, value] = [0, 1].map(|index| block.get_rws(step, index).stack_value()); self.address.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs b/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs index e38ffd9d80..8804392410 100644 --- a/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/mul_div_mod.rs @@ -121,9 +121,8 @@ impl ExecutionGadget for MulDivModGadget { step: &ExecStep, ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let indices = [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]]; - let [pop1, pop2, push] = indices.map(|idx| block.rws[idx].stack_value()); - let (a, b, c, d) = match step.opcode.unwrap() { + let [pop1, pop2, push] = [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); + let (a, b, c, d) = match step.opcode().unwrap() { OpcodeId::MUL => (pop1, pop2, U256::from(0), push), OpcodeId::DIV => (push, pop2, pop1 - push * pop2, pop1), OpcodeId::MOD => ( diff --git a/zkevm-circuits/src/evm_circuit/execution/mulmod.rs b/zkevm-circuits/src/evm_circuit/execution/mulmod.rs index ad146ca1a6..3986b16d9d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/mulmod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/mulmod.rs @@ -116,9 +116,7 @@ impl ExecutionGadget for MulModGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let [r, n, b, a] = [3, 2, 1, 0] - .map(|idx| step.rw_indices[idx]) - .map(|idx| block.rws[idx].stack_value()); + let [r, n, b, a] = [3, 2, 1, 0].map(|index| block.get_rws(step, index).stack_value()); self.words[0].assign(region, offset, Some(a.to_le_bytes()))?; self.words[1].assign(region, offset, Some(b.to_le_bytes()))?; self.words[2].assign(region, offset, Some(n.to_le_bytes()))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/not.rs b/zkevm-circuits/src/evm_circuit/execution/not.rs index 7a076021b3..37ddcc3f1b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/not.rs +++ b/zkevm-circuits/src/evm_circuit/execution/not.rs @@ -74,8 +74,7 @@ impl ExecutionGadget for NotGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let [input, output] = - [step.rw_indices[0], step.rw_indices[1]].map(|idx| block.rws[idx].stack_value()); + let [input, output] = [0, 1].map(|index| block.get_rws(step, index).stack_value()); self.input .assign(region, offset, Some(input.to_le_bytes()))?; self.output diff --git a/zkevm-circuits/src/evm_circuit/execution/origin.rs b/zkevm-circuits/src/evm_circuit/execution/origin.rs index f47f186463..f53d0e2099 100644 --- a/zkevm-circuits/src/evm_circuit/execution/origin.rs +++ b/zkevm-circuits/src/evm_circuit/execution/origin.rs @@ -72,7 +72,7 @@ impl ExecutionGadget for OriginGadget { _: &Call, step: &ExecStep, ) -> Result<(), Error> { - let origin = block.rws[step.rw_indices[1]].stack_value(); + let origin = block.get_rws(step, 1).stack_value(); // Assing TxId. self.tx_id diff --git a/zkevm-circuits/src/evm_circuit/execution/pc.rs b/zkevm-circuits/src/evm_circuit/execution/pc.rs index 9180cb5452..5e2a2b2e11 100644 --- a/zkevm-circuits/src/evm_circuit/execution/pc.rs +++ b/zkevm-circuits/src/evm_circuit/execution/pc.rs @@ -72,7 +72,7 @@ impl ExecutionGadget for PcGadget { self.same_context.assign_exec_step(region, offset, step)?; self.value - .assign(region, offset, Some(step.program_counter.to_le_bytes()))?; + .assign(region, offset, Some(step.program_counter().to_le_bytes()))?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/execution/pop.rs b/zkevm-circuits/src/evm_circuit/execution/pop.rs index 77c4ad3c3f..93103a4ae3 100644 --- a/zkevm-circuits/src/evm_circuit/execution/pop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/pop.rs @@ -60,7 +60,7 @@ impl ExecutionGadget for PopGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let value = block.rws[step.rw_indices[0]].stack_value(); + let value = block.get_rws(step, 0).stack_value(); self.phase2_value .assign(region, offset, region.word_rlc(value))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/push.rs b/zkevm-circuits/src/evm_circuit/execution/push.rs index d21549b1d7..75c1add43c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/push.rs +++ b/zkevm-circuits/src/evm_circuit/execution/push.rs @@ -126,9 +126,9 @@ impl ExecutionGadget for PushGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); - let value = block.rws[step.rw_indices[0]].stack_value(); + let value = block.get_rws(step, 0).stack_value(); self.value .assign(region, offset, Some(value.to_le_bytes()))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs index b2fad3fbdf..4fef4795e9 100644 --- a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs +++ b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs @@ -245,10 +245,10 @@ impl ExecutionGadget for ReturnRevertGadget { self.opcode.assign( region, offset, - Value::known(F::from(step.opcode.unwrap().as_u64())), + Value::known(F::from(step.opcode().unwrap().as_u64())), )?; - let [memory_offset, length] = [0, 1].map(|i| block.rws[step.rw_indices[i]].stack_value()); + let [memory_offset, length] = [0, 1].map(|index| block.get_rws(step, index).stack_value()); let range = self.range.assign(region, offset, memory_offset, length)?; self.memory_expansion .assign(region, offset, step.memory_word_size(), [range])?; @@ -277,7 +277,7 @@ impl ExecutionGadget for ReturnRevertGadget { if call.is_create() && call.is_success { let values: Vec<_> = (3..3 + length.as_usize()) - .map(|i| block.rws[step.rw_indices[i]].memory_value()) + .map(|index| block.get_rws(step, index).memory_value()) .collect(); let mut code_hash = CodeDB::hash(&values).to_fixed_bytes(); code_hash.reverse(); diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs index d8af064cf6..4a16767f58 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs @@ -176,7 +176,7 @@ impl ExecutionGadget for ReturnDataCopyGadget { self.same_context.assign_exec_step(region, offset, step)?; let [dest_offset, data_offset, size] = - [0, 1, 2].map(|i| block.rws[step.rw_indices[i as usize]].stack_value()); + [0, 1, 2].map(|index| block.get_rws(step, index).stack_value()); self.data_offset.assign( region, @@ -194,7 +194,7 @@ impl ExecutionGadget for ReturnDataCopyGadget { (5, CallContextFieldTag::LastCalleeReturnDataLength), ] .map(|(i, tag)| { - let rw = block.rws[step.rw_indices[i as usize]]; + let rw = block.get_rws(step, i); assert_eq!(rw.field_tag(), Some(tag as u64)); rw.call_context_value() }); diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs index 51aac27a97..60aaafa0f0 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatasize.rs @@ -69,7 +69,7 @@ impl ExecutionGadget for ReturnDataSizeGadget { step: &ExecStep, ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let return_data_size = block.rws[step.rw_indices[1]].stack_value(); + let return_data_size = block.get_rws(step, 1).stack_value(); self.return_data_size.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/execution/sar.rs b/zkevm-circuits/src/evm_circuit/execution/sar.rs index 97e1e2c259..87dbd318a5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sar.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sar.rs @@ -266,8 +266,7 @@ impl ExecutionGadget for SarGadget { step: &ExecStep, ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let indices = [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]]; - let [shift, a, b] = indices.map(|idx| block.rws[idx].stack_value()); + let [shift, a, b] = [0, 1, 2].map(|idx| block.get_rws(step, idx).stack_value()); self.shift .assign(region, offset, Some(shift.to_le_bytes()))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs b/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs index 95a8b451df..7398ced5ed 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sdiv_smod.rs @@ -150,14 +150,13 @@ impl ExecutionGadget for SignedDivModGadget { step: &ExecStep, ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let indices = [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]]; - let [pop1, pop2, push] = indices.map(|idx| block.rws[idx].stack_value()); + let [pop1, pop2, push] = [0, 1, 2].map(|idx| block.get_rws(step, idx).stack_value()); let pop1_abs = get_abs(pop1); let pop2_abs = get_abs(pop2); let push_abs = get_abs(push); let is_pop1_neg = is_neg(pop1); let is_pop2_neg = is_neg(pop2); - let (quotient, divisor, remainder, dividend) = match step.opcode.unwrap() { + let (quotient, divisor, remainder, dividend) = match step.opcode().unwrap() { OpcodeId::SDIV => ( push, pop2, diff --git a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs index 9d0f938bb0..b170e88360 100644 --- a/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs +++ b/zkevm-circuits/src/evm_circuit/execution/selfbalance.rs @@ -78,7 +78,7 @@ impl ExecutionGadget for SelfbalanceGadget { ), )?; - let self_balance = block.rws[step.rw_indices[2]].stack_value(); + let self_balance = block.get_rws(step, 2).stack_value(); self.phase2_self_balance .assign(region, offset, region.word_rlc(self_balance))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index 3f8c11f714..63191e4e79 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -114,8 +114,7 @@ impl ExecutionGadget for Sha3Gadget { self.same_context.assign_exec_step(region, offset, step)?; let [memory_offset, size, sha3_output] = - [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]] - .map(|idx| block.rws[idx].stack_value()); + [0, 1, 2].map(|idx| block.get_rws(step, idx).stack_value()); let memory_address = self .memory_address .assign(region, offset, memory_offset, size)?; @@ -132,7 +131,7 @@ impl ExecutionGadget for Sha3Gadget { )?; let values: Vec = (3..3 + (size.low_u64() as usize)) - .map(|i| block.rws[step.rw_indices[i]].memory_value()) + .map(|i| block.get_rws(step, i).memory_value()) .collect(); let rlc_acc = region diff --git a/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs b/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs index 409114b3cf..798a1101fe 100644 --- a/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs +++ b/zkevm-circuits/src/evm_circuit/execution/shl_shr.rs @@ -163,8 +163,7 @@ impl ExecutionGadget for ShlShrGadget { step: &ExecStep, ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let indices = [step.rw_indices[0], step.rw_indices[1], step.rw_indices[2]]; - let [pop1, pop2, push] = indices.map(|idx| block.rws[idx].stack_value()); + let [pop1, pop2, push] = [0, 1, 2].map(|idx| block.get_rws(step, idx).stack_value()); let shf0 = u64::from(pop1.to_le_bytes()[0]); let shf_lt256 = pop1 .to_le_bytes() @@ -180,7 +179,7 @@ impl ExecutionGadget for ShlShrGadget { U256::from(0) }; - let (quotient, remainder, dividend) = match step.opcode.unwrap() { + let (quotient, remainder, dividend) = match step.opcode().unwrap() { OpcodeId::SHL => (pop2, U256::from(0), push), OpcodeId::SHR => (push, pop2 - push * divisor, pop2), _ => unreachable!(), diff --git a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs index d243fef860..8ee8357385 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signed_comparator.rs @@ -153,7 +153,7 @@ impl ExecutionGadget for SignedComparatorGadget { ) -> Result<(), Error> { self.same_context.assign_exec_step(region, offset, step)?; - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); // SLT opcode is the default check in the SCMP gadget. Swap rw for SGT. self.is_sgt.assign( @@ -163,11 +163,11 @@ impl ExecutionGadget for SignedComparatorGadget { F::from(OpcodeId::SGT.as_u8() as u64), )?; let indices = if opcode == OpcodeId::SGT { - [step.rw_indices[1], step.rw_indices[0]] + [1, 0] } else { - [step.rw_indices[0], step.rw_indices[1]] + [0, 1] }; - let [a, b] = indices.map(|idx| block.rws[idx].stack_value()); + let [a, b] = indices.map(|idx| block.get_rws(step, idx).stack_value()); let a_le_bytes = a.to_le_bytes(); let b_le_bytes = b.to_le_bytes(); diff --git a/zkevm-circuits/src/evm_circuit/execution/signextend.rs b/zkevm-circuits/src/evm_circuit/execution/signextend.rs index 02427df086..ba16143688 100644 --- a/zkevm-circuits/src/evm_circuit/execution/signextend.rs +++ b/zkevm-circuits/src/evm_circuit/execution/signextend.rs @@ -166,8 +166,8 @@ impl ExecutionGadget for SignextendGadget { self.same_context.assign_exec_step(region, offset, step)?; // Inputs/Outputs - let index = block.rws[step.rw_indices[0]].stack_value().to_le_bytes(); - let value = block.rws[step.rw_indices[1]].stack_value().to_le_bytes(); + let index = block.get_rws(step, 0).stack_value().to_le_bytes(); + let value = block.get_rws(step, 1).stack_value().to_le_bytes(); self.index.assign(region, offset, Some(index))?; self.value.assign(region, offset, Some(value))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/sload.rs b/zkevm-circuits/src/evm_circuit/execution/sload.rs index da64916ac1..32759f9aa1 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sload.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sload.rs @@ -117,19 +117,18 @@ impl ExecutionGadget for SloadGadget { .expect("unexpected Address -> Scalar conversion failure"), ), )?; - - let [key, value] = - [step.rw_indices[4], step.rw_indices[6]].map(|idx| block.rws[idx].stack_value()); + let key = block.get_rws(step, 4).stack_value(); + let value = block.get_rws(step, 6).stack_value(); self.phase2_key .assign(region, offset, region.word_rlc(key))?; self.phase2_value .assign(region, offset, region.word_rlc(value))?; - let (_, committed_value) = block.rws[step.rw_indices[5]].aux_pair(); + let (_, committed_value) = block.get_rws(step, 5).aux_pair(); self.phase2_committed_value .assign(region, offset, region.word_rlc(committed_value))?; - let (_, is_warm) = block.rws[step.rw_indices[7]].tx_access_list_value_pair(); + let (_, is_warm) = block.get_rws(step, 7).tx_access_list_value_pair(); self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/sstore.rs b/zkevm-circuits/src/evm_circuit/execution/sstore.rs index dcc8468dc9..22f18d0a9d 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sstore.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sstore.rs @@ -184,24 +184,24 @@ impl ExecutionGadget for SstoreGadget { ), )?; - let [key, value] = - [step.rw_indices[5], step.rw_indices[6]].map(|idx| block.rws[idx].stack_value()); + let key = block.get_rws(step, 5).stack_value(); + let value = block.get_rws(step, 6).stack_value(); self.phase2_key .assign(region, offset, region.word_rlc(key))?; self.phase2_value .assign(region, offset, region.word_rlc(value))?; - let (_, value_prev, _, original_value) = block.rws[step.rw_indices[7]].storage_value_aux(); + let (_, value_prev, _, original_value) = block.get_rws(step, 7).storage_value_aux(); self.phase2_value_prev .assign(region, offset, region.word_rlc(value_prev))?; self.phase2_original_value .assign(region, offset, region.word_rlc(original_value))?; - let (_, is_warm) = block.rws[step.rw_indices[8]].tx_access_list_value_pair(); + let (_, is_warm) = block.get_rws(step, 8).tx_access_list_value_pair(); self.is_warm .assign(region, offset, Value::known(F::from(is_warm as u64)))?; - let (tx_refund, tx_refund_prev) = block.rws[step.rw_indices[9]].tx_refund_value_pair(); + let (tx_refund, tx_refund_prev) = block.get_rws(step, 9).tx_refund_value_pair(); self.tx_refund_prev .assign(region, offset, Value::known(F::from(tx_refund_prev)))?; @@ -209,7 +209,7 @@ impl ExecutionGadget for SstoreGadget { region, offset, Value::known(F::from(GasCost::SSTORE_SENTRY.0)), - Value::known(F::from(step.gas_left)), + Value::known(F::from(step.gas_left.into())), )?; self.gas_cost diff --git a/zkevm-circuits/src/evm_circuit/execution/stop.rs b/zkevm-circuits/src/evm_circuit/execution/stop.rs index b79d6dc906..5d47894a9a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/stop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/stop.rs @@ -116,10 +116,10 @@ impl ExecutionGadget for StopGadget { self.is_out_of_range.assign( region, offset, - F::from(code.bytes.len() as u64) - F::from(step.program_counter), + F::from(code.bytes.len() as u64) - F::from(step.program_counter()), )?; - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; diff --git a/zkevm-circuits/src/evm_circuit/execution/swap.rs b/zkevm-circuits/src/evm_circuit/execution/swap.rs index 951d8922f7..7238aa5833 100644 --- a/zkevm-circuits/src/evm_circuit/execution/swap.rs +++ b/zkevm-circuits/src/evm_circuit/execution/swap.rs @@ -70,8 +70,8 @@ impl ExecutionGadget for SwapGadget { self.same_context.assign_exec_step(region, offset, step)?; for (cell, value) in self.phase2_values.iter().zip( - [step.rw_indices[0], step.rw_indices[1]] - .map(|idx| block.rws[idx].stack_value()) + [0, 1] + .map(|index| block.get_rws(step, index).stack_value()) .iter(), ) { cell.assign(region, offset, region.word_rlc(*value))?; diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index 326a4a9a08..b0693794da 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -7,8 +7,12 @@ use crate::{ }, util::Expr, }; -use bus_mapping::evm::OpcodeId; -use eth_types::{Field, ToWord}; +use bus_mapping::{ + circuit_input_builder::ExecState, + error::{ExecError, OogError}, + evm::OpcodeId, +}; +use eth_types::{evm_unimplemented, Field, ToWord}; use halo2_proofs::{ circuit::Value, plonk::{Advice, Column, ConstraintSystem, Error, Expression}, @@ -121,6 +125,154 @@ impl Display for ExecutionState { write!(f, "{:?}", self) } } +impl From<&ExecError> for ExecutionState { + fn from(error: &ExecError) -> Self { + match error { + ExecError::InvalidOpcode => ExecutionState::ErrorInvalidOpcode, + ExecError::StackOverflow | ExecError::StackUnderflow => ExecutionState::ErrorStack, + ExecError::WriteProtection => ExecutionState::ErrorWriteProtection, + ExecError::Depth => ExecutionState::ErrorDepth, + ExecError::InsufficientBalance => ExecutionState::ErrorInsufficientBalance, + ExecError::ContractAddressCollision => ExecutionState::ErrorContractAddressCollision, + ExecError::InvalidCreationCode => ExecutionState::ErrorInvalidCreationCode, + ExecError::InvalidJump => ExecutionState::ErrorInvalidJump, + ExecError::ReturnDataOutOfBounds => ExecutionState::ErrorReturnDataOutOfBound, + ExecError::CodeStoreOutOfGas => ExecutionState::ErrorOutOfGasCodeStore, + ExecError::MaxCodeSizeExceeded => ExecutionState::ErrorMaxCodeSizeExceeded, + ExecError::OutOfGas(oog_error) => match oog_error { + OogError::Constant => ExecutionState::ErrorOutOfGasConstant, + OogError::StaticMemoryExpansion => { + ExecutionState::ErrorOutOfGasStaticMemoryExpansion + } + OogError::DynamicMemoryExpansion => { + ExecutionState::ErrorOutOfGasDynamicMemoryExpansion + } + OogError::MemoryCopy => ExecutionState::ErrorOutOfGasMemoryCopy, + OogError::AccountAccess => ExecutionState::ErrorOutOfGasAccountAccess, + OogError::CodeStore => ExecutionState::ErrorOutOfGasCodeStore, + OogError::Log => ExecutionState::ErrorOutOfGasLOG, + OogError::Exp => ExecutionState::ErrorOutOfGasEXP, + OogError::Sha3 => ExecutionState::ErrorOutOfGasSHA3, + OogError::Call => ExecutionState::ErrorOutOfGasCall, + OogError::SloadSstore => ExecutionState::ErrorOutOfGasSloadSstore, + OogError::Create2 => ExecutionState::ErrorOutOfGasCREATE2, + OogError::SelfDestruct => ExecutionState::ErrorOutOfGasSELFDESTRUCT, + }, + } + } +} +impl From<&ExecStep> for ExecutionState { + fn from(step: &ExecStep) -> Self { + if let Some(error) = step.error.as_ref() { + return error.into(); + } + match step.exec_state { + ExecState::Op(op) => { + if op.is_dup() { + return ExecutionState::DUP; + } + if op.is_push() { + return ExecutionState::PUSH; + } + if op.is_swap() { + return ExecutionState::SWAP; + } + if op.is_log() { + return ExecutionState::LOG; + } + + macro_rules! dummy { + ($name:expr) => {{ + evm_unimplemented!("{:?} is implemented with DummyGadget", $name); + $name + }}; + } + + match op { + OpcodeId::ADD | OpcodeId::SUB => ExecutionState::ADD_SUB, + OpcodeId::ADDMOD => ExecutionState::ADDMOD, + OpcodeId::ADDRESS => ExecutionState::ADDRESS, + OpcodeId::BALANCE => ExecutionState::BALANCE, + OpcodeId::MUL | OpcodeId::DIV | OpcodeId::MOD => ExecutionState::MUL_DIV_MOD, + OpcodeId::MULMOD => ExecutionState::MULMOD, + OpcodeId::SDIV | OpcodeId::SMOD => ExecutionState::SDIV_SMOD, + OpcodeId::EQ | OpcodeId::LT | OpcodeId::GT => ExecutionState::CMP, + OpcodeId::SLT | OpcodeId::SGT => ExecutionState::SCMP, + OpcodeId::SIGNEXTEND => ExecutionState::SIGNEXTEND, + OpcodeId::STOP => ExecutionState::STOP, + OpcodeId::AND => ExecutionState::BITWISE, + OpcodeId::XOR => ExecutionState::BITWISE, + OpcodeId::OR => ExecutionState::BITWISE, + OpcodeId::NOT => ExecutionState::NOT, + OpcodeId::EXP => ExecutionState::EXP, + OpcodeId::POP => ExecutionState::POP, + OpcodeId::PUSH32 => ExecutionState::PUSH, + OpcodeId::BYTE => ExecutionState::BYTE, + OpcodeId::MLOAD => ExecutionState::MEMORY, + OpcodeId::MSTORE => ExecutionState::MEMORY, + OpcodeId::MSTORE8 => ExecutionState::MEMORY, + OpcodeId::JUMPDEST => ExecutionState::JUMPDEST, + OpcodeId::JUMP => ExecutionState::JUMP, + OpcodeId::JUMPI => ExecutionState::JUMPI, + OpcodeId::GASPRICE => ExecutionState::GASPRICE, + OpcodeId::PC => ExecutionState::PC, + OpcodeId::MSIZE => ExecutionState::MSIZE, + OpcodeId::CALLER => ExecutionState::CALLER, + OpcodeId::CALLVALUE => ExecutionState::CALLVALUE, + OpcodeId::EXTCODEHASH => ExecutionState::EXTCODEHASH, + OpcodeId::EXTCODESIZE => ExecutionState::EXTCODESIZE, + OpcodeId::BLOCKHASH => ExecutionState::BLOCKHASH, + OpcodeId::TIMESTAMP | OpcodeId::NUMBER | OpcodeId::GASLIMIT => { + ExecutionState::BLOCKCTXU64 + } + OpcodeId::COINBASE => ExecutionState::BLOCKCTXU160, + OpcodeId::DIFFICULTY | OpcodeId::BASEFEE => ExecutionState::BLOCKCTXU256, + OpcodeId::GAS => ExecutionState::GAS, + OpcodeId::SAR => ExecutionState::SAR, + OpcodeId::SELFBALANCE => ExecutionState::SELFBALANCE, + OpcodeId::SHA3 => ExecutionState::SHA3, + OpcodeId::SHL | OpcodeId::SHR => ExecutionState::SHL_SHR, + OpcodeId::SLOAD => ExecutionState::SLOAD, + OpcodeId::SSTORE => ExecutionState::SSTORE, + OpcodeId::CALLDATASIZE => ExecutionState::CALLDATASIZE, + OpcodeId::CALLDATACOPY => ExecutionState::CALLDATACOPY, + OpcodeId::CHAINID => ExecutionState::CHAINID, + OpcodeId::ISZERO => ExecutionState::ISZERO, + OpcodeId::CALL + | OpcodeId::CALLCODE + | OpcodeId::DELEGATECALL + | OpcodeId::STATICCALL => ExecutionState::CALL_OP, + OpcodeId::ORIGIN => ExecutionState::ORIGIN, + OpcodeId::CODECOPY => ExecutionState::CODECOPY, + OpcodeId::CALLDATALOAD => ExecutionState::CALLDATALOAD, + OpcodeId::CODESIZE => ExecutionState::CODESIZE, + OpcodeId::EXTCODECOPY => ExecutionState::EXTCODECOPY, + OpcodeId::RETURN | OpcodeId::REVERT => ExecutionState::RETURN_REVERT, + OpcodeId::RETURNDATASIZE => ExecutionState::RETURNDATASIZE, + OpcodeId::RETURNDATACOPY => ExecutionState::RETURNDATACOPY, + // dummy ops + OpcodeId::CREATE => dummy!(ExecutionState::CREATE), + OpcodeId::CREATE2 => dummy!(ExecutionState::CREATE2), + OpcodeId::SELFDESTRUCT => dummy!(ExecutionState::SELFDESTRUCT), + _ => unimplemented!("unimplemented opcode {:?}", op), + } + } + ExecState::BeginTx => ExecutionState::BeginTx, + ExecState::EndTx => ExecutionState::EndTx, + ExecState::EndBlock => ExecutionState::EndBlock, + } + } +} + +pub trait HasExecutionState { + fn execution_state(&self) -> ExecutionState; +} + +impl HasExecutionState for ExecStep { + fn execution_state(&self) -> ExecutionState { + ExecutionState::from(self) + } +} impl ExecutionState { pub(crate) const fn as_u64(&self) -> u64 { @@ -549,12 +701,10 @@ impl Step { ) -> Result<(), Error> { self.state .execution_state - .assign(region, offset, step.execution_state as usize)?; - self.state.rw_counter.assign( - region, - offset, - Value::known(F::from(step.rw_counter as u64)), - )?; + .assign(region, offset, step.execution_state() as usize)?; + self.state + .rw_counter + .assign(region, offset, Value::known(F::from(step.rwc.into())))?; self.state .call_id .assign(region, offset, Value::known(F::from(call.call_id as u64)))?; @@ -572,16 +722,16 @@ impl Step { self.state.program_counter.assign( region, offset, - Value::known(F::from(step.program_counter)), + Value::known(F::from(step.program_counter())), )?; self.state.stack_pointer.assign( region, offset, - Value::known(F::from(step.stack_pointer as u64)), + Value::known(F::from(step.stack_pointer())), )?; self.state .gas_left - .assign(region, offset, Value::known(F::from(step.gas_left)))?; + .assign(region, offset, Value::known(F::from(step.gas_left.0)))?; self.state.memory_word_size.assign( region, offset, diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index 5453227232..de2a71bad5 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -5,7 +5,6 @@ use crate::{ }, table::Table, }, - table::RwTableTag, util::{query_expression, Challenges, Expr}, witness::{Block, ExecStep, Rw, RwMap}, }; @@ -626,7 +625,7 @@ pub(crate) fn is_precompiled(address: &Address) -> bool { /// Helper struct to read rw operations from a step sequentially. pub(crate) struct StepRws<'a> { rws: &'a RwMap, - rw_indices: &'a Vec<(RwTableTag, usize)>, + step: &'a ExecStep, offset: usize, } @@ -635,7 +634,7 @@ impl<'a> StepRws<'a> { pub(crate) fn new(block: &'a Block, step: &'a ExecStep) -> Self { Self { rws: &block.rws, - rw_indices: &step.rw_indices, + step, offset: 0, } } @@ -645,7 +644,7 @@ impl<'a> StepRws<'a> { } /// Return the next rw operation from the step. pub(crate) fn next(&mut self) -> Rw { - let rw = self.rws[self.rw_indices[self.offset]]; + let rw = self.rws[self.step.rw_index(self.offset)]; self.offset += 1; rw } diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 6858c37d56..fba7e7770b 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -76,12 +76,15 @@ impl SameContextGadget { offset: usize, step: &ExecStep, ) -> Result<(), Error> { - let opcode = step.opcode.unwrap(); + let opcode = step.opcode().unwrap(); self.opcode .assign(region, offset, Value::known(F::from(opcode.as_u64())))?; - self.sufficient_gas_left - .assign(region, offset, F::from(step.gas_left - step.gas_cost))?; + self.sufficient_gas_left.assign( + region, + offset, + F::from(step.gas_left.0 - step.gas_cost.0), + )?; Ok(()) } @@ -222,8 +225,7 @@ impl RestoreContextGadget { [U256::zero(); 9] } else { [0, 1, 2, 3, 4, 5, 6, 7, 8] - .map(|i| step.rw_indices[i + rw_offset]) - .map(|idx| block.rws[idx].call_context_value()) + .map(|i| block.get_rws(step, i + rw_offset).call_context_value()) }; for (cell, value) in [ diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 338cae170d..4f69656e36 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -10,7 +10,10 @@ use crate::{ Block, BlockContext, Bytecode, MptUpdateRow, MptUpdates, Rw, RwMap, RwRow, Transaction, }, }; -use bus_mapping::circuit_input_builder::{CopyDataType, CopyEvent, CopyStep, ExpEvent}; +use bus_mapping::{ + circuit_input_builder::{CopyDataType, CopyEvent, CopyStep, ExpEvent}, + operation::Target, +}; use core::iter::once; use eth_types::{Field, ToLittleEndian, ToScalar, Word, U256}; use gadgets::{ @@ -327,6 +330,24 @@ impl From for usize { } } +impl From for RwTableTag { + fn from(t: Target) -> Self { + match t { + Target::Memory => Self::Memory, + Target::Stack => Self::Stack, + Target::Storage => Self::AccountStorage, + Target::TxAccessListAccount => Self::TxAccessListAccount, + Target::TxAccessListAccountStorage => Self::TxAccessListAccountStorage, + Target::TxRefund => Self::TxRefund, + Target::Account => Self::Account, + Target::CallContext => Self::CallContext, + Target::TxReceipt => Self::TxReceipt, + Target::TxLog => Self::TxLog, + Target::Start => Self::Start, + } + } +} + /// Tag for an AccountField in RwTable #[derive(Clone, Copy, Debug, EnumIter, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AccountFieldTag { diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index 019706ad0e..dde790dd39 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -9,9 +9,8 @@ pub use bytecode::Bytecode; mod mpt; pub use mpt::{MptUpdate, MptUpdateRow, MptUpdates}; mod rw; +pub use bus_mapping::circuit_input_builder::ExecStep; pub use rw::{Rw, RwMap, RwRow}; -mod step; -pub use step::ExecStep; mod tx; pub use bus_mapping::circuit_input_builder::Call; pub use tx::Transaction; diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index a8f52d822e..f74a6681c6 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -14,7 +14,7 @@ use bus_mapping::{ use eth_types::{Address, Field, ToLittleEndian, ToScalar, Word}; use halo2_proofs::circuit::Value; -use super::{step::step_convert, tx::tx_convert, Bytecode, ExecStep, RwMap, Transaction}; +use super::{tx::tx_convert, Bytecode, ExecStep, Rw, RwMap, Transaction}; // TODO: Remove fields that are duplicated in`eth_block` /// Block is the struct used by all circuits, which contains all the needed @@ -55,18 +55,9 @@ pub struct Block { } impl Block { - /// For each tx, for each step, print the rwc at the beginning of the step, - /// and all the rw operations of the step. - pub(crate) fn debug_print_txs_steps_rw_ops(&self) { - for (tx_idx, tx) in self.txs.iter().enumerate() { - println!("tx {}", tx_idx); - for step in &tx.steps { - println!(" step {:?} rwc: {}", step.execution_state, step.rw_counter); - for rw_ref in &step.rw_indices { - println!(" - {:?}", self.rws[*rw_ref]); - } - } - } + /// Get a read-write record + pub(crate) fn get_rws(&self, step: &ExecStep, index: usize) -> Rw { + self.rws[step.rw_index(index)] } } @@ -251,8 +242,8 @@ pub fn block_convert( .enumerate() .map(|(idx, tx)| tx_convert(tx, idx + 1)) .collect(), - end_block_not_last: step_convert(&block.block_steps.end_block_not_last), - end_block_last: step_convert(&block.block_steps.end_block_last), + end_block_not_last: block.block_steps.end_block_not_last.clone(), + end_block_last: block.block_steps.end_block_last.clone(), bytecodes: code_db .0 .values() diff --git a/zkevm-circuits/src/witness/rw.rs b/zkevm-circuits/src/witness/rw.rs index 994c3c3194..074166005a 100644 --- a/zkevm-circuits/src/witness/rw.rs +++ b/zkevm-circuits/src/witness/rw.rs @@ -1,7 +1,10 @@ #![allow(missing_docs)] use std::collections::HashMap; -use bus_mapping::operation::{self, AccountField, CallContextField, TxLogField, TxReceiptField}; +use bus_mapping::{ + exec_trace::OperationRef, + operation::{self, AccountField, CallContextField, TxLogField, TxReceiptField}, +}; use eth_types::{Address, Field, ToAddress, ToLittleEndian, ToScalar, Word, U256}; use halo2_proofs::{circuit::Value, halo2curves::bn256::Fr}; use itertools::Itertools; @@ -25,6 +28,16 @@ impl std::ops::Index<(RwTableTag, usize)> for RwMap { &self.0.get(&tag).unwrap()[idx] } } + +impl std::ops::Index for RwMap { + type Output = Rw; + + fn index(&self, OperationRef(tag, idx): OperationRef) -> &Self::Output { + let tag: RwTableTag = tag.into(); + &self.0.get(&tag).unwrap()[idx] + } +} + impl RwMap { /// Check rw_counter is continuous and starting from 1 pub fn check_rw_counter_sanity(&self) { diff --git a/zkevm-circuits/src/witness/step.rs b/zkevm-circuits/src/witness/step.rs deleted file mode 100644 index 2baa55690f..0000000000 --- a/zkevm-circuits/src/witness/step.rs +++ /dev/null @@ -1,242 +0,0 @@ -use bus_mapping::{ - circuit_input_builder, - error::{ExecError, OogError}, - evm::OpcodeId, - operation, -}; -use eth_types::evm_unimplemented; - -use crate::{ - evm_circuit::{ - param::{N_BYTES_WORD, STACK_CAPACITY}, - step::ExecutionState, - }, - table::RwTableTag, -}; - -/// Step executed in a transaction -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct ExecStep { - /// The index in the Transaction calls - pub call_index: usize, - /// The indices in the RW trace incurred in this step - pub rw_indices: Vec<(RwTableTag, usize)>, - /// Number of rw operations performed via a copy event in this step. - pub copy_rw_counter_delta: u64, - /// The execution state for the step - pub execution_state: ExecutionState, - /// The Read/Write counter before the step - pub rw_counter: usize, - /// The program counter - pub program_counter: u64, - /// The stack pointer - pub stack_pointer: usize, - /// The amount of gas left - pub gas_left: u64, - /// The gas cost in this step - pub gas_cost: u64, - /// The memory size in bytes - pub memory_size: u64, - /// The counter for reversible writes at the beginning of the step - pub reversible_write_counter: usize, - /// The number of reversible writes from this step - pub reversible_write_counter_delta: usize, - /// The counter for log index within tx - pub log_id: usize, - /// The opcode corresponds to the step - pub opcode: Option, -} - -impl ExecStep { - /// The memory size in word **before** this step - pub fn memory_word_size(&self) -> u64 { - // EVM always pads the memory size to word size - // https://github.com/ethereum/go-ethereum/blob/master/core/vm/interpreter.go#L212-L216 - // Thus, the memory size must be a multiple of 32 bytes. - assert_eq!(self.memory_size % N_BYTES_WORD as u64, 0); - self.memory_size / N_BYTES_WORD as u64 - } -} - -impl From<&ExecError> for ExecutionState { - fn from(error: &ExecError) -> Self { - match error { - ExecError::InvalidOpcode => ExecutionState::ErrorInvalidOpcode, - ExecError::StackOverflow | ExecError::StackUnderflow => ExecutionState::ErrorStack, - ExecError::WriteProtection => ExecutionState::ErrorWriteProtection, - ExecError::Depth => ExecutionState::ErrorDepth, - ExecError::InsufficientBalance => ExecutionState::ErrorInsufficientBalance, - ExecError::ContractAddressCollision => ExecutionState::ErrorContractAddressCollision, - ExecError::InvalidCreationCode => ExecutionState::ErrorInvalidCreationCode, - ExecError::InvalidJump => ExecutionState::ErrorInvalidJump, - ExecError::ReturnDataOutOfBounds => ExecutionState::ErrorReturnDataOutOfBound, - ExecError::CodeStoreOutOfGas => ExecutionState::ErrorOutOfGasCodeStore, - ExecError::MaxCodeSizeExceeded => ExecutionState::ErrorMaxCodeSizeExceeded, - ExecError::OutOfGas(oog_error) => match oog_error { - OogError::Constant => ExecutionState::ErrorOutOfGasConstant, - OogError::StaticMemoryExpansion => { - ExecutionState::ErrorOutOfGasStaticMemoryExpansion - } - OogError::DynamicMemoryExpansion => { - ExecutionState::ErrorOutOfGasDynamicMemoryExpansion - } - OogError::MemoryCopy => ExecutionState::ErrorOutOfGasMemoryCopy, - OogError::AccountAccess => ExecutionState::ErrorOutOfGasAccountAccess, - OogError::CodeStore => ExecutionState::ErrorOutOfGasCodeStore, - OogError::Log => ExecutionState::ErrorOutOfGasLOG, - OogError::Exp => ExecutionState::ErrorOutOfGasEXP, - OogError::Sha3 => ExecutionState::ErrorOutOfGasSHA3, - OogError::Call => ExecutionState::ErrorOutOfGasCall, - OogError::SloadSstore => ExecutionState::ErrorOutOfGasSloadSstore, - OogError::Create2 => ExecutionState::ErrorOutOfGasCREATE2, - OogError::SelfDestruct => ExecutionState::ErrorOutOfGasSELFDESTRUCT, - }, - } - } -} - -impl From<&circuit_input_builder::ExecStep> for ExecutionState { - fn from(step: &circuit_input_builder::ExecStep) -> Self { - if let Some(error) = step.error.as_ref() { - return error.into(); - } - match step.exec_state { - circuit_input_builder::ExecState::Op(op) => { - if op.is_dup() { - return ExecutionState::DUP; - } - if op.is_push() { - return ExecutionState::PUSH; - } - if op.is_swap() { - return ExecutionState::SWAP; - } - if op.is_log() { - return ExecutionState::LOG; - } - - macro_rules! dummy { - ($name:expr) => {{ - evm_unimplemented!("{:?} is implemented with DummyGadget", $name); - $name - }}; - } - - match op { - OpcodeId::ADD | OpcodeId::SUB => ExecutionState::ADD_SUB, - OpcodeId::ADDMOD => ExecutionState::ADDMOD, - OpcodeId::ADDRESS => ExecutionState::ADDRESS, - OpcodeId::BALANCE => ExecutionState::BALANCE, - OpcodeId::MUL | OpcodeId::DIV | OpcodeId::MOD => ExecutionState::MUL_DIV_MOD, - OpcodeId::MULMOD => ExecutionState::MULMOD, - OpcodeId::SDIV | OpcodeId::SMOD => ExecutionState::SDIV_SMOD, - OpcodeId::EQ | OpcodeId::LT | OpcodeId::GT => ExecutionState::CMP, - OpcodeId::SLT | OpcodeId::SGT => ExecutionState::SCMP, - OpcodeId::SIGNEXTEND => ExecutionState::SIGNEXTEND, - OpcodeId::STOP => ExecutionState::STOP, - OpcodeId::AND => ExecutionState::BITWISE, - OpcodeId::XOR => ExecutionState::BITWISE, - OpcodeId::OR => ExecutionState::BITWISE, - OpcodeId::NOT => ExecutionState::NOT, - OpcodeId::EXP => ExecutionState::EXP, - OpcodeId::POP => ExecutionState::POP, - OpcodeId::PUSH32 => ExecutionState::PUSH, - OpcodeId::BYTE => ExecutionState::BYTE, - OpcodeId::MLOAD => ExecutionState::MEMORY, - OpcodeId::MSTORE => ExecutionState::MEMORY, - OpcodeId::MSTORE8 => ExecutionState::MEMORY, - OpcodeId::JUMPDEST => ExecutionState::JUMPDEST, - OpcodeId::JUMP => ExecutionState::JUMP, - OpcodeId::JUMPI => ExecutionState::JUMPI, - OpcodeId::GASPRICE => ExecutionState::GASPRICE, - OpcodeId::PC => ExecutionState::PC, - OpcodeId::MSIZE => ExecutionState::MSIZE, - OpcodeId::CALLER => ExecutionState::CALLER, - OpcodeId::CALLVALUE => ExecutionState::CALLVALUE, - OpcodeId::EXTCODEHASH => ExecutionState::EXTCODEHASH, - OpcodeId::EXTCODESIZE => ExecutionState::EXTCODESIZE, - OpcodeId::BLOCKHASH => ExecutionState::BLOCKHASH, - OpcodeId::TIMESTAMP | OpcodeId::NUMBER | OpcodeId::GASLIMIT => { - ExecutionState::BLOCKCTXU64 - } - OpcodeId::COINBASE => ExecutionState::BLOCKCTXU160, - OpcodeId::DIFFICULTY | OpcodeId::BASEFEE => ExecutionState::BLOCKCTXU256, - OpcodeId::GAS => ExecutionState::GAS, - OpcodeId::SAR => ExecutionState::SAR, - OpcodeId::SELFBALANCE => ExecutionState::SELFBALANCE, - OpcodeId::SHA3 => ExecutionState::SHA3, - OpcodeId::SHL | OpcodeId::SHR => ExecutionState::SHL_SHR, - OpcodeId::SLOAD => ExecutionState::SLOAD, - OpcodeId::SSTORE => ExecutionState::SSTORE, - OpcodeId::CALLDATASIZE => ExecutionState::CALLDATASIZE, - OpcodeId::CALLDATACOPY => ExecutionState::CALLDATACOPY, - OpcodeId::CHAINID => ExecutionState::CHAINID, - OpcodeId::ISZERO => ExecutionState::ISZERO, - OpcodeId::CALL - | OpcodeId::CALLCODE - | OpcodeId::DELEGATECALL - | OpcodeId::STATICCALL => ExecutionState::CALL_OP, - OpcodeId::ORIGIN => ExecutionState::ORIGIN, - OpcodeId::CODECOPY => ExecutionState::CODECOPY, - OpcodeId::CALLDATALOAD => ExecutionState::CALLDATALOAD, - OpcodeId::CODESIZE => ExecutionState::CODESIZE, - OpcodeId::EXTCODECOPY => ExecutionState::EXTCODECOPY, - OpcodeId::RETURN | OpcodeId::REVERT => ExecutionState::RETURN_REVERT, - OpcodeId::RETURNDATASIZE => ExecutionState::RETURNDATASIZE, - OpcodeId::RETURNDATACOPY => ExecutionState::RETURNDATACOPY, - // dummy ops - OpcodeId::CREATE => dummy!(ExecutionState::CREATE), - OpcodeId::CREATE2 => dummy!(ExecutionState::CREATE2), - OpcodeId::SELFDESTRUCT => dummy!(ExecutionState::SELFDESTRUCT), - _ => unimplemented!("unimplemented opcode {:?}", op), - } - } - circuit_input_builder::ExecState::BeginTx => ExecutionState::BeginTx, - circuit_input_builder::ExecState::EndTx => ExecutionState::EndTx, - circuit_input_builder::ExecState::EndBlock => ExecutionState::EndBlock, - } - } -} - -pub(super) fn step_convert(step: &circuit_input_builder::ExecStep) -> ExecStep { - ExecStep { - call_index: step.call_index, - rw_indices: step - .bus_mapping_instance - .iter() - .map(|x| { - let tag = match x.target() { - operation::Target::Memory => RwTableTag::Memory, - operation::Target::Stack => RwTableTag::Stack, - operation::Target::Storage => RwTableTag::AccountStorage, - operation::Target::TxAccessListAccount => RwTableTag::TxAccessListAccount, - operation::Target::TxAccessListAccountStorage => { - RwTableTag::TxAccessListAccountStorage - } - operation::Target::TxRefund => RwTableTag::TxRefund, - operation::Target::Account => RwTableTag::Account, - operation::Target::CallContext => RwTableTag::CallContext, - operation::Target::TxReceipt => RwTableTag::TxReceipt, - operation::Target::TxLog => RwTableTag::TxLog, - operation::Target::Start => RwTableTag::Start, - }; - (tag, x.as_usize()) - }) - .collect(), - copy_rw_counter_delta: step.copy_rw_counter_delta, - execution_state: ExecutionState::from(step), - rw_counter: usize::from(step.rwc), - program_counter: usize::from(step.pc) as u64, - stack_pointer: STACK_CAPACITY - step.stack_size, - gas_left: step.gas_left.0, - gas_cost: step.gas_cost.as_u64(), - opcode: match step.exec_state { - circuit_input_builder::ExecState::Op(op) => Some(op), - _ => None, - }, - memory_size: step.memory_size as u64, - reversible_write_counter: step.reversible_write_counter, - reversible_write_counter_delta: step.reversible_write_counter_delta, - log_id: step.log_id, - } -} diff --git a/zkevm-circuits/src/witness/tx.rs b/zkevm-circuits/src/witness/tx.rs index a6119f12fd..38be201d3f 100644 --- a/zkevm-circuits/src/witness/tx.rs +++ b/zkevm-circuits/src/witness/tx.rs @@ -4,10 +4,10 @@ use halo2_proofs::circuit::Value; use crate::{evm_circuit::util::rlc, table::TxContextFieldTag, util::Challenges}; -use super::{step::step_convert, Call, ExecStep}; +use super::{Call, ExecStep}; /// Transaction in a witness block -#[derive(Debug, Default, Clone, PartialEq, Eq)] +#[derive(Debug, Default, Clone)] pub struct Transaction { /// The transaction identifier in the block pub id: usize, @@ -135,6 +135,6 @@ pub(super) fn tx_convert(tx: &circuit_input_builder::Transaction, id: usize) -> call_data_length: tx.tx.call_data.len(), call_data_gas_cost: tx.tx.call_data_gas_cost(), calls: tx.calls().to_vec(), - steps: tx.steps().iter().map(step_convert).collect(), + steps: tx.steps().to_vec(), } } From d6923a91fa73503c8096bc2e829b145682844ac6 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 12 May 2023 17:19:04 +0800 Subject: [PATCH 040/102] example 1 phase error --- .../src/circuit_tools/cached_region.rs | 19 +-- .../src/circuit_tools/tests/util.rs | 160 ++++++++++++------ zkevm-circuits/src/mpt_circuit.rs | 3 +- zkevm-circuits/src/mpt_circuit/table.rs | 10 +- 4 files changed, 119 insertions(+), 73 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools/cached_region.rs b/zkevm-circuits/src/circuit_tools/cached_region.rs index b3ba3be262..fed66b51f1 100644 --- a/zkevm-circuits/src/circuit_tools/cached_region.rs +++ b/zkevm-circuits/src/circuit_tools/cached_region.rs @@ -14,31 +14,16 @@ use std::{ use super::cell_manager::TableType; -trait Indexd { - fn indexed(&self) -> Vec<&T>; -} - -impl Indexd for crate::util::Challenges { - fn indexed(&self) -> Vec<&T> { - vec![&self.evm_word, &self.keccak_input, &self.lookup_input] - } -} pub trait ChallengeSet { fn indexed(&self) -> Vec<&Value>; } -impl ChallengeSet for crate::util::Challenges> { +impl]>> ChallengeSet for V { fn indexed(&self) -> Vec<&Value> { - vec![&self.evm_word, &self.keccak_input, &self.lookup_input] + self.as_ref().iter().collect() } } -// pub struct EvmChallenges { -// pub evm_word: T, -// pub keccak_input: T, -// pub lookup_input: T, -// } - pub struct CachedRegion<'r, 'b, F: Field, C: ChallengeSet> { region: &'r mut Region<'b, F>, advice: Vec>, diff --git a/zkevm-circuits/src/circuit_tools/tests/util.rs b/zkevm-circuits/src/circuit_tools/tests/util.rs index 2d06c628d5..75f06a85a5 100644 --- a/zkevm-circuits/src/circuit_tools/tests/util.rs +++ b/zkevm-circuits/src/circuit_tools/tests/util.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use std::vec; use crate::circuit_tools::cached_region::{self, ChallengeSet}; -use crate::circuit_tools::cell_manager::{Cell, CellManager, PhaseConfig, SingleTable, TableType}; +use crate::circuit_tools::cell_manager::{Cell, CellManager, PhaseConfig, SingleTable, TableType, CellType_}; use crate::circuit_tools::constraint_builder::ConstraintBuilder; use crate::circuit_tools::memory::Memory; use crate::util::{Expr, query_expression}; @@ -11,7 +11,9 @@ use crate::circuit_tools::{table::LookupTable, cached_region::CachedRegion}; use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::circuit::{SimpleFloorPlanner, layouter, Layouter, Region}; -use halo2_proofs::plonk::{Any, Circuit, FirstPhase, Challenge, SecondPhase, ThirdPhase}; +use halo2_proofs::dev::MockProver; +use halo2_proofs::halo2curves::bn256::Fr; +use halo2_proofs::plonk::{Any, Circuit, FirstPhase, Challenge, SecondPhase, ThirdPhase, Fixed}; use halo2_proofs::{ circuit::{AssignedCell, Value}, plonk::{ConstraintSystem, Advice, Column, Error, Expression, VirtualCells}, @@ -29,10 +31,12 @@ use halo2_proofs::{ const MAX_DEG: usize = 5; const CM_HEIGHT: usize = 10; const COPY_COL_NUM: usize = 10; +const REGION_HEIGHT: usize = 10; +#[derive(Clone)] pub struct TestTable { - pub a: Column, - pub b: Column, + pub a: Column, + pub b: Column, } impl LookupTable for TestTable { @@ -49,9 +53,11 @@ impl LookupTable for TestTable { #[derive(Clone)] pub struct TestConfig { + pub(crate) q_enable: Column, pub(crate) q_count: Column, pub(crate) cell_columns: Vec>, pub(crate) cell_gadget: CellGadget, + pub(crate) table: TestTable, } @@ -63,34 +69,46 @@ impl TestConfig { ) -> Self { // Get columns - let q_count = meta.advice_column_in(FirstPhase); - let cell_columns: Vec> = (0..2).map(|_| meta.advice_column_in(ThirdPhase)) - .chain((3..5).map(|_| meta.advice_column_in(SecondPhase))) - .chain((6..9).map(|_| meta.advice_column())) - .collect(); + let q_enable = meta.fixed_column(); + let q_count = meta.advice_column(); + let cell_columns = (0..10) + .map(|i| + match i { + 0..=2 => meta.advice_column_in(ThirdPhase), + 3..=5 => meta.advice_column_in(SecondPhase), + 6..=9 => meta.advice_column_in(FirstPhase), + _ => unreachable!(), + } + ).collect::>(); // Init cell manager and constraint builder let phase_config: PhaseConfig = PhaseConfig::new::(vec![&table], 2, 3); - let mut cm = CellManager::new( - meta, - CM_HEIGHT, - &cell_columns, - 0, - phase_config, - COPY_COL_NUM - ); + let mut cm = CellManager::new(meta, CM_HEIGHT,&cell_columns,0,phase_config,COPY_COL_NUM ); let mut cb = ConstraintBuilder::new(MAX_DEG, Some(cm)); - // Init Gadgets - let cell_gadget = CellGadget::configure( - &mut cb, - // Convert Challenge into Expression - query_expression(meta, |meta| meta.query_challenge(r1)) - ); + let mut cell_gadget = CellGadget::default(); + meta.create_gate("Test Gate", |meta| { + // Config row counts + circuit!([meta, cb], { + ifx!(f!(q_enable) => { + require!(a!(q_count, 1) => a!(q_count) + 1.expr()); + }) + }); + // Init Gadgets + cell_gadget = CellGadget::configure( + &mut cb, + // Convert Challenge into Expression + meta.query_challenge(r1), + ); + cb.generate_constraints() + }); + Self { + q_enable, q_count, cell_columns, cell_gadget, + table, } } @@ -99,20 +117,49 @@ impl TestConfig { layouter: &mut impl Layouter, r1: Value, ) -> Result<(), Error> { - // layouter.assign_region( - // || "cell gadget", - // |mut region| { - // let cached_region = cached_region::CachedRegion::new(&mut region); - // self.cell_gadget.assign(&mut region, 0, r1) - // }, - // ) - unimplemented!() + layouter.assign_region( + || "cell gadget", + |mut region| { + + for offset in 0..50 { + assignf!(region, (self.q_enable, offset) => 1.scalar())?; + assign!(region, (self.q_count, offset) => offset.scalar())?; + } + // Value of challenge is obtained from layouter. + // We query it once during synthesis and + // make it accessable across Config through CachedRegion. + let challenges = [r1]; + let mut cached_region = cached_region::CachedRegion::new(&mut region, &challenges, self.cell_columns.clone(), REGION_HEIGHT, 0); + self.cell_gadget.assign(&mut cached_region, 0) + }, + ) + } + + fn load_fixed_table( + &self, + layouter: &mut impl Layouter, + ) -> Result<(), Error> { + // We can use different region for lookup tables, + // since they are not related to cell gadgets. + layouter.assign_region( + || "fixed table", + |mut region| { + for offset in 0..50 { + // Don't need CachedRegion here since we don't cache intermediate values. + assignf!(region, (self.table.a, offset) => offset.scalar())?; + assignf!(region, (self.table.b, offset) => (offset + 1).scalar())?; + } + Ok(()) + }, + ) } + } #[derive(Clone, Debug, Default)] pub struct CellGadget { + // (a, b) in lookup // a + r1 * b == c // where r1 is phase1 challenge // a == d @@ -127,13 +174,15 @@ impl CellGadget { pub fn configure(cb: &mut ConstraintBuilder, r1: Expression) -> Self { let a = cb.query_cell(); let b = cb.query_cell(); - let c = cb.query_byte(); + // c depends on Phase1 Challenge r1 + let c = cb.query_cell_with_type(CellType_::StoragePhase2); let d = cb.query_cell(); circuit!([meta, cb], { require!((a, b) => @format!("test_lookup")); require!(c => a.expr() + b.expr() * r1); require!(a => d.expr()); }); + CellGadget { a, b, c, d } } @@ -141,32 +190,32 @@ impl CellGadget { &self, region: &mut CachedRegion<'_, '_, F, C>, offset: usize, - r1: Value ) -> Result<(), Error>{ + // All challenges are returned as defined struct or Vec<&Value>, + // we map them to Vec for calculations. + let mut r = F::one(); + region.challenges().indexed()[0].map(|r_val| r = r_val); + + // Assign values to cells self.a.assign(region, offset, 2u64.scalar())?; self.b.assign(region, offset, 3u64.scalar())?; - - // self.c.assign( - // region, - // offset, - // 2u64.scalar() + 3u64.scalar() * r1 - // )?; - - assign!(region, (self.a.column(), offset) => 2u64.scalar())?; - assign!(region, (self.b.column(), offset) => 3u64.scalar())?; - // assign!(region, (self.c.column(), offset) => 2u64.scalar() + 3u64.scalar() * r1)?; - assign!(region, (self.d.column(), offset) => 2u64.scalar())?; - - region.get_advice(1, 1, Rotation::cur()); + self.c.assign( + region, + offset, + F::from(2u64) + F::from(3u64) * r + )?; + self.d.assign(region, offset, 2u64.scalar())?; Ok(()) } - } - +#[derive(Clone, Debug, Default)] struct TestCircuit { - config: TestConfig, + // Don't need anything in this struct, + // since we don't have precomputed data from outside + // and Config & Challenges are passed to synthesize. + _phantom: F, } impl Circuit for TestCircuit { @@ -183,9 +232,10 @@ impl Circuit for TestCircuit { // Build the table and challenge outside // since zkevm use them accross circuits let table = TestTable { - a: meta.advice_column(), - b: meta.advice_column(), + a: meta.fixed_column(), + b: meta.fixed_column(), }; + let _dummy_phase1 = meta.advice_column(); let r1 = meta.challenge_usable_after(FirstPhase); let config = TestConfig::new(meta, table, r1); @@ -195,14 +245,18 @@ impl Circuit for TestCircuit { fn synthesize( &self, (config, r1): Self::Config, - layouter: impl halo2_proofs::circuit::Layouter + mut layouter: impl halo2_proofs::circuit::Layouter ) -> Result<(), Error> { let r1 = layouter.get_challenge(r1); + config.load_fixed_table(&mut layouter); config.assign(&mut layouter, r1) } } #[test] fn test() { - + let circuit = TestCircuit::::default(); + let prover = MockProver::::run(5, &circuit, vec![]).unwrap(); + prover.assert_satisfied_par(); + } \ No newline at end of file diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 48240bab2c..d58c07cde2 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -207,7 +207,7 @@ impl MPTConfig { memory.allocate(meta, main_memory()); let mut ctx = MPTContext { - mpt_table: mpt_table, + mpt_table, rlp_item: rlp_item.clone(), challenges: challenges.clone(), r: challenges.keccak_input(), @@ -362,6 +362,7 @@ impl MPTConfig { node.values.len(), offset ); + // Decompose RLP for (idx, bytes) in node.values.iter().enumerate() { let is_nibbles = node.extension_branch.is_some() && idx == ExtensionBranchRowType::KeyC as usize; diff --git a/zkevm-circuits/src/mpt_circuit/table.rs b/zkevm-circuits/src/mpt_circuit/table.rs index ef733c0ea8..ba1bb8a071 100644 --- a/zkevm-circuits/src/mpt_circuit/table.rs +++ b/zkevm-circuits/src/mpt_circuit/table.rs @@ -1,10 +1,10 @@ use eth_types::Field; -use halo2_proofs::plonk::{Column, Any}; +use halo2_proofs::{plonk::{Column, Any}, circuit::Value}; use strum_macros::EnumIter; use crate::{ circuit_tools::cell_manager::TableType, - circuit_tools::table::LookupTable, + circuit_tools::{table::LookupTable, cached_region::ChallengeSet}, table::KeccakTable }; @@ -47,3 +47,9 @@ impl LookupTable for KeccakTable { } } + +impl ChallengeSet for crate::util::Challenges> { + fn indexed(&self) -> Vec<&Value> { + vec![&self.evm_word, &self.keccak_input, &self.lookup_input] + } +} \ No newline at end of file From 5dba7f758b38f651bc6a63c51d98693c503064d8 Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Mon, 15 May 2023 16:42:41 +0800 Subject: [PATCH 041/102] Set keccak logs to debug level (#1405) ### Description Keccak circuit logs messages that make CI logs hard to reason. We can set it from "INFO" level to "DEBUG" level to suppress the messages in the CI output but still keep it for develoepers. https://github.com/privacy-scaling-explorations/zkevm-circuits/actions/runs/4955284960/jobs/8864549606#step:13:50
Details

``` test mock_prover::serial_test_exp_circuit_multiple_transfers_0 ... ok [2023-05-12T05:00:22Z INFO integration_tests::integration_test_circuits] test Keccak circuit, block: #1 - Transfer 0 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] - Post absorb: [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Lookups: 2 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Columns: 7 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] - Post padding: [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Lookups: 1 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Columns: 10 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] - Post theta: [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Lookups: 14 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Columns: 38 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] - Post rho/pi: [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Lookups: 53 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Columns: 191 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] - Post chi: [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Lookups: [52](https://github.com/privacy-scaling-explorations/zkevm-circuits/actions/runs/4955284960/jobs/8864549606#step:13:53) [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Columns: 195 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] - Post squeeze: [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Lookups: 1 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Columns: 198 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Degree: 4 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Minimum rows: [61](https://github.com/privacy-scaling-explorations/zkevm-circuits/actions/runs/4955284960/jobs/8864549606#step:13:62) [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Total Lookups: 123 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] Total Columns: 198 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] num unused cells: 229 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] part_size absorb: 4 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] part_size theta: 2 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] part_size theta c: 2 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] part_size theta t: 3 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] part_size rho/pi: 3 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] part_size chi base: 3 [2023-05-12T05:00:22Z INFO zkevm_circuits::keccak_circuit] uniform part sizes: [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] ```

### Issue Link ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update --- zkevm-circuits/src/keccak_circuit.rs | 62 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/zkevm-circuits/src/keccak_circuit.rs b/zkevm-circuits/src/keccak_circuit.rs index 983cb45894..029ec196a6 100644 --- a/zkevm-circuits/src/keccak_circuit.rs +++ b/zkevm-circuits/src/keccak_circuit.rs @@ -42,7 +42,7 @@ use halo2_proofs::{ plonk::{Column, ConstraintSystem, Error, Expression, Fixed, TableColumn, VirtualCells}, poly::Rotation, }; -use log::info; +use log::debug; /// KeccakConfig #[derive(Clone, Debug)] @@ -178,9 +178,9 @@ impl SubCircuitConfig for KeccakCircuitConfig { decode::expr(absorb_res), absorb_result.expr(), ); - info!("- Post absorb:"); - info!("Lookups: {}", lookup_counter); - info!("Columns: {}", cell_manager.get_width()); + debug!("- Post absorb:"); + debug!("Lookups: {}", lookup_counter); + debug!("Columns: {}", cell_manager.get_width()); total_lookup_counter += lookup_counter; // Process inputs. @@ -220,9 +220,9 @@ impl SubCircuitConfig for KeccakCircuitConfig { for _ in input_bytes.iter() { is_paddings.push(cell_manager.query_cell(meta)); } - info!("- Post padding:"); - info!("Lookups: {}", lookup_counter); - info!("Columns: {}", cell_manager.get_width()); + debug!("- Post padding:"); + debug!("Lookups: {}", lookup_counter); + debug!("Columns: {}", cell_manager.get_width()); total_lookup_counter += lookup_counter; // Theta @@ -278,9 +278,9 @@ impl SubCircuitConfig for KeccakCircuitConfig { } } s = os.clone(); - info!("- Post theta:"); - info!("Lookups: {}", lookup_counter); - info!("Columns: {}", cell_manager.get_width()); + debug!("- Post theta:"); + debug!("Lookups: {}", lookup_counter); + debug!("Columns: {}", cell_manager.get_width()); total_lookup_counter += lookup_counter; // Rho/Pi @@ -366,9 +366,9 @@ impl SubCircuitConfig for KeccakCircuitConfig { }); lookup_counter += 1; } - info!("- Post rho/pi:"); - info!("Lookups: {}", lookup_counter); - info!("Columns: {}", cell_manager.get_width()); + debug!("- Post rho/pi:"); + debug!("Lookups: {}", lookup_counter); + debug!("Columns: {}", cell_manager.get_width()); total_lookup_counter += lookup_counter; // Chi @@ -446,9 +446,9 @@ impl SubCircuitConfig for KeccakCircuitConfig { cb.require_equal("next row check", s[i][j].clone(), s_next[i][j].clone()); } } - info!("- Post chi:"); - info!("Lookups: {}", lookup_counter); - info!("Columns: {}", cell_manager.get_width()); + debug!("- Post chi:"); + debug!("Lookups: {}", lookup_counter); + debug!("Columns: {}", cell_manager.get_width()); total_lookup_counter += lookup_counter; let mut lookup_counter = 0; @@ -486,9 +486,9 @@ impl SubCircuitConfig for KeccakCircuitConfig { .unwrap(), true, ); - info!("- Post squeeze:"); - info!("Lookups: {}", lookup_counter); - info!("Columns: {}", cell_manager.get_width()); + debug!("- Post squeeze:"); + debug!("Lookups: {}", lookup_counter); + debug!("Columns: {}", cell_manager.get_width()); total_lookup_counter += lookup_counter; // The round constraints that we've been building up till now @@ -823,21 +823,21 @@ impl SubCircuitConfig for KeccakCircuitConfig { meta.annotate_lookup_column(col, || format!("KECCAK_pack_table_{}", idx)) }); - info!("Degree: {}", meta.degree()); - info!("Minimum rows: {}", meta.minimum_rows()); - info!("Total Lookups: {}", total_lookup_counter); - info!("Total Columns: {}", cell_manager.get_width()); - info!("num unused cells: {}", cell_manager.get_num_unused_cells()); - info!("part_size absorb: {}", get_num_bits_per_absorb_lookup()); - info!("part_size theta: {}", get_num_bits_per_theta_c_lookup()); - info!( + debug!("Degree: {}", meta.degree()); + debug!("Minimum rows: {}", meta.minimum_rows()); + debug!("Total Lookups: {}", total_lookup_counter); + debug!("Total Columns: {}", cell_manager.get_width()); + debug!("num unused cells: {}", cell_manager.get_num_unused_cells()); + debug!("part_size absorb: {}", get_num_bits_per_absorb_lookup()); + debug!("part_size theta: {}", get_num_bits_per_theta_c_lookup()); + debug!( "part_size theta c: {}", get_num_bits_per_lookup(THETA_C_LOOKUP_RANGE) ); - info!("part_size theta t: {}", get_num_bits_per_lookup(4)); - info!("part_size rho/pi: {}", get_num_bits_per_rho_pi_lookup()); - info!("part_size chi base: {}", get_num_bits_per_base_chi_lookup()); - info!( + debug!("part_size theta t: {}", get_num_bits_per_lookup(4)); + debug!("part_size rho/pi: {}", get_num_bits_per_rho_pi_lookup()); + debug!("part_size chi base: {}", get_num_bits_per_base_chi_lookup()); + debug!( "uniform part sizes: {:?}", target_part_sizes(get_num_bits_per_theta_c_lookup()) ); From ead0b3dfabf0dfd6d63a4f986ef70a94715a6b73 Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Tue, 16 May 2023 18:29:23 +0800 Subject: [PATCH 042/102] Move stats to bin (#1407) ### Description We have 4 utility commands that show us statistics of different circuits. Currently, these features were compiled with the tests, causing dependency and feature flags management troubles. The commands also cause confusion with the ignored test flags. We can enjoy many benefits if we keep these commands in binary executables. - We can compile them on demand. We remove compilation overheads for the main components and tests. - Stats commands are confined in the `bin` directory, so we don't have confusing testing code. ### Issue Link It was #1246. After exploring, I found room for improving the status quo. ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - Move the underlying logics of `make stats_state_circuit`, `make stats_evm_circuit`, `make stats_copy_circuit`, and `make evm_exec_steps_occupancy` to `bin` directory. - Add a feature flag, `stats` for these specific tools. - Remove `DisplayTable` and replace all its use with `cli-table`'s feature. This has the benefit that the line of codes in the codebase reflects more on the core zkevm functionality. After we used `cli-table`, the table also rendered differently, see images below. - Move `cli-table` from `dev-dependency` to `dependency`, but as an optional dependency. - Remove dead dependency `subtle` and `criterion` After: Screenshot 2023-05-14 at 3 26 43 PM Before: Screenshot 2023-05-14 at 3 27 53 PM ### Rationale - Some undesirable results were introduced. - We left the Instrument struct unchanged. The `Instrument` is buried deep in the ExecutionConfig. We intend to deal with it in future PRs to keep the diff of this one slim. - We changed some visibilities of structs and functions in evm circuits from `pub(crate)` to `pub` ### How Has This Been Tested? Manual run `make stats_state_circuit`, `make stats_evm_circuit`, `make stats_copy_circuit`, and `make evm_exec_steps_occupancy` and see if they work. --- Cargo.lock | 100 +--------- Makefile | 8 +- zkevm-circuits/Cargo.toml | 9 +- .../src/{stats.rs => bin/stats/helpers.rs} | 95 +++------ zkevm-circuits/src/bin/stats/main.rs | 185 ++++++++++++++++++ zkevm-circuits/src/copy_circuit.rs | 42 ---- zkevm-circuits/src/evm_circuit.rs | 156 +-------------- zkevm-circuits/src/evm_circuit/execution.rs | 4 +- zkevm-circuits/src/evm_circuit/param.rs | 10 +- zkevm-circuits/src/evm_circuit/step.rs | 6 +- zkevm-circuits/src/evm_circuit/table.rs | 2 +- .../src/evm_circuit/util/instrumentation.rs | 46 ++--- zkevm-circuits/src/lib.rs | 3 - zkevm-circuits/src/state_circuit.rs | 37 ---- 14 files changed, 272 insertions(+), 431 deletions(-) rename zkevm-circuits/src/{stats.rs => bin/stats/helpers.rs} (79%) create mode 100644 zkevm-circuits/src/bin/stats/main.rs diff --git a/Cargo.lock b/Cargo.lock index 8c80f9102a..e0d8e8fceb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -496,12 +496,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - [[package]] name = "cc" version = "1.0.79" @@ -557,17 +551,6 @@ dependencies = [ "zkevm-circuits", ] -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "bitflags", - "textwrap 0.11.0", - "unicode-width", -] - [[package]] name = "clap" version = "3.2.23" @@ -582,7 +565,7 @@ dependencies = [ "once_cell", "strsim 0.10.0", "termcolor", - "textwrap 0.16.0", + "textwrap", ] [[package]] @@ -824,42 +807,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "criterion" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" -dependencies = [ - "atty", - "cast", - "clap 2.34.0", - "criterion-plot", - "csv", - "itertools", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_cbor", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" -dependencies = [ - "cast", - "itertools", -] - [[package]] name = "crossbeam-channel" version = "0.5.6" @@ -2150,12 +2097,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - [[package]] name = "halo2_proofs" version = "0.1.0" @@ -3014,12 +2955,6 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - [[package]] name = "opaque-debug" version = "0.2.3" @@ -4166,16 +4101,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" version = "1.0.152" @@ -4537,7 +4462,7 @@ version = "0.1.0" dependencies = [ "anyhow", "bus-mapping", - "clap 3.2.23", + "clap", "env_logger", "eth-types", "ethers-core", @@ -4567,15 +4492,6 @@ dependencies = [ "zkevm-circuits", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "textwrap" version = "0.16.0" @@ -4622,16 +4538,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -5273,7 +5179,6 @@ dependencies = [ "array-init", "bus-mapping", "cli-table", - "criterion", "ctor", "ecc", "ecdsa 0.1.0", @@ -5304,5 +5209,4 @@ dependencies = [ "snark-verifier", "strum", "strum_macros", - "subtle", ] diff --git a/Makefile b/Makefile index f8dabed664..58656a3448 100644 --- a/Makefile +++ b/Makefile @@ -58,15 +58,15 @@ exp_bench: ## Run Exp Circuit benchmarks circuit_benches: evm_bench state_bench ## Run All Circuit benchmarks stats_state_circuit: # Print a table with State Circuit stats by ExecState/opcode - @cargo test -p zkevm-circuits --features=test,warn-unimplemented get_state_states_stats -- --nocapture --ignored + @cargo run --bin stats --features stats -- state stats_evm_circuit: # Print a table with EVM Circuit stats by ExecState/opcode - @cargo test -p zkevm-circuits --features=test,warn-unimplemented get_evm_states_stats -- --nocapture --ignored + @cargo run --bin stats --features stats -- evm stats_copy_circuit: # Print a table with Copy Circuit stats by ExecState/opcode - @cargo test -p zkevm-circuits --features=test,warn-unimplemented get_copy_states_stats -- --nocapture --ignored + @cargo run --bin stats --features stats -- copy evm_exec_steps_occupancy: # Print a table for each EVM-CellManager CellType with the top 10 occupancy ExecutionSteps associated - @cargo test -p zkevm-circuits --release get_exec_steps_occupancy --features=test,warn-unimplemented -- --nocapture --ignored + @cargo run --bin stats --features stats -- exec .PHONY: clippy doc fmt test test_benches test-all evm_bench state_bench circuit_benches evm_exec_steps_occupancy stats_state_circuit stats_evm_circuit stats_copy_circuit help diff --git a/zkevm-circuits/Cargo.toml b/zkevm-circuits/Cargo.toml index 433f1a99b5..3f0bd6641f 100644 --- a/zkevm-circuits/Cargo.toml +++ b/zkevm-circuits/Cargo.toml @@ -33,20 +33,18 @@ maingate = { git = "https://github.com/privacy-scaling-explorations/halo2wrong" integer = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_04_20" } libsecp256k1 = "0.7" num-bigint = { version = "0.4" } -subtle = "2.4" rand_chacha = "0.3" snark-verifier = { git = "https://github.com/privacy-scaling-explorations/snark-verifier", tag = "v2023_04_20", default-features = false, features = ["loader_halo2", "system_halo2"] } +cli-table = { version = "0.4", optional = true } [dev-dependencies] bus-mapping = { path = "../bus-mapping", features = ["test"] } -criterion = "0.3" ctor = "0.1.22" ethers-signers = "0.17.0" hex = "0.4.3" itertools = "0.10.1" mock = { path = "../mock" } pretty_assertions = "1.0.0" -cli-table = "0.4" serde = { version = "1.0.130", features = ["derive"] } serde_json = "1.0.78" @@ -55,3 +53,8 @@ default = [] test = ["ethers-signers", "mock", "bus-mapping/test"] test-circuits = [] warn-unimplemented = ["eth-types/warn-unimplemented"] +stats = ["warn-unimplemented", "dep:cli-table"] + +[[bin]] +name = "stats" +required-features = ["stats"] diff --git a/zkevm-circuits/src/stats.rs b/zkevm-circuits/src/bin/stats/helpers.rs similarity index 79% rename from zkevm-circuits/src/stats.rs rename to zkevm-circuits/src/bin/stats/helpers.rs index ed43527497..01117a48c0 100644 --- a/zkevm-circuits/src/stats.rs +++ b/zkevm-circuits/src/bin/stats/helpers.rs @@ -1,61 +1,17 @@ use std::cmp::Ordering; -use crate::evm_circuit::step::ExecutionState; use bus_mapping::{ circuit_input_builder::{self, CircuitsParams, ExecState}, mock::BlockData, }; +use cli_table::{ + format::{Justify, Separator}, + print_stdout, Table, WithTitle, +}; use eth_types::{bytecode, evm_types::OpcodeId, geth_types::GethData, Address, Bytecode, ToWord}; use mock::{eth, test_ctx::TestContext, MOCK_ACCOUNTS}; use strum::IntoEnumIterator; - -/// Helper type to print formatted tables in MarkDown -pub(crate) struct DisplayTable { - header: [String; N], - rows: Vec<[String; N]>, -} - -impl DisplayTable { - pub(crate) fn new(header: [String; N]) -> Self { - Self { - header, - rows: Vec::new(), - } - } - fn push_row(&mut self, row: [String; N]) { - self.rows.push(row) - } - fn print_row(row: &[String; N], rows_width: &[usize; N]) { - for (i, h) in row.iter().enumerate() { - if i == 0 { - print!("|"); - } - print!(" {:width$} |", h, width = rows_width[i]); - } - println!(); - } - pub(crate) fn print(&self) { - let mut rows_width = [0; N]; - for row in std::iter::once(&self.header).chain(self.rows.iter()) { - for (i, s) in row.iter().enumerate() { - if s.len() > rows_width[i] { - rows_width[i] = s.len(); - } - } - } - Self::print_row(&self.header, &rows_width); - for (i, width) in rows_width.iter().enumerate() { - if i == 0 { - print!("|"); - } - print!(" {:- Bytecode { @@ -106,12 +62,34 @@ pub(crate) fn bytecode_prefix_op_big_rws(opcode: OpcodeId) -> Bytecode { } } +/// Wrap f64 for both sorting and pretty formatting +#[derive(PartialEq, PartialOrd)] +struct PrettyF64(f64); + +impl std::fmt::Display for PrettyF64 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:1.3}", self.0) + } +} + +impl From for PrettyF64 { + fn from(value: f64) -> Self { + Self(value) + } +} + +#[derive(Table)] struct Row { + #[table(title = "Execution State")] state: ExecutionState, + #[table(title = "Opcode")] opcode: OpcodeId, + #[table(title = "Height", justify = "Justify::Right")] height: usize, + #[table(title = "Gas Cost", justify = "Justify::Right")] gas_cost: u64, - height_per_gas: f64, + #[table(title = "Height per Gas", justify = "Justify::Right")] + height_per_gas: PrettyF64, } /// This function prints to stdout a table with all the implemented states @@ -161,7 +139,6 @@ pub(crate) fn print_circuit_stats_by_states( STOP }; - let mut table = DisplayTable::new(["state", "opcode", "h", "g", "h/g"].map(|s| s.into())); let mut rows = vec![]; for state in implemented_states { if !fn_filter(state) { @@ -251,7 +228,7 @@ pub(crate) fn print_circuit_stats_by_states( opcode, height, gas_cost, - height_per_gas: height as f64 / gas_cost as f64, + height_per_gas: (height as f64 / gas_cost as f64).into(), }); } } @@ -261,16 +238,6 @@ pub(crate) fn print_circuit_stats_by_states( .unwrap_or(Ordering::Greater) }); - for row in rows.iter() { - let row = [ - format!("{:?}", row.state), - format!("{:?}", row.opcode), - format!("{}", row.height), - format!("{}", row.gas_cost), - format!("{:1.3}", row.height_per_gas), - ]; - table.push_row(row); - } - - table.print(); + print_stdout(rows.with_title().separator(Separator::builder().build())) + .expect("the table renders"); } diff --git a/zkevm-circuits/src/bin/stats/main.rs b/zkevm-circuits/src/bin/stats/main.rs new file mode 100644 index 0000000000..30c8fc9a27 --- /dev/null +++ b/zkevm-circuits/src/bin/stats/main.rs @@ -0,0 +1,185 @@ +use cli_table::{print_stdout, Cell, Style, Table}; +use eth_types::{bytecode, evm_types::OpcodeId, ToWord}; +use halo2_proofs::{ + halo2curves::bn256::Fr, + plonk::{Circuit, ConstraintSystem}, +}; +mod helpers; +use helpers::{bytecode_prefix_op_big_rws, print_circuit_stats_by_states}; +use itertools::Itertools; +use mock::MOCK_ACCOUNTS; +use std::env; +use zkevm_circuits::evm_circuit::{ + param::{LOOKUP_CONFIG, N_BYTE_LOOKUPS, N_COPY_COLUMNS, N_PHASE1_COLUMNS, N_PHASE2_COLUMNS}, + step::ExecutionState, + EvmCircuit, +}; +fn main() { + let args: Vec = env::args().collect(); + + match &args[1][..] { + "evm" => evm_states_stats(), + "state" => state_states_stats(), + "copy" => copy_states_stats(), + "exec" => get_exec_steps_occupancy(), + &_ => unreachable!("Unsupported arg"), + } +} + +/// Prints the stats of EVM circuit per execution state. +fn evm_states_stats() { + print_circuit_stats_by_states( + |state| { + // TODO: Enable CREATE/CREATE2 once they are supported + !matches!( + state, + ExecutionState::ErrorInvalidOpcode + | ExecutionState::CREATE + | ExecutionState::CREATE2 + | ExecutionState::SELFDESTRUCT + ) + }, + |opcode| match opcode { + OpcodeId::RETURNDATACOPY => { + bytecode! { + PUSH1(0x00) // retLength + PUSH1(0x00) // retOffset + PUSH1(0x00) // argsLength + PUSH1(0x00) // argsOffset + PUSH1(0x00) // value + PUSH32(MOCK_ACCOUNTS[3].to_word()) + PUSH32(0x1_0000) // gas + CALL + PUSH2(0x01) // size + PUSH2(0x00) // offset + PUSH2(0x00) // destOffset + } + } + _ => bytecode! { + PUSH2(0x40) + PUSH2(0x50) + }, + }, + |_, state, _| state.get_step_height_option().unwrap(), + ); +} + +/// Prints the stats of State circuit per execution state. +fn state_states_stats() { + print_circuit_stats_by_states( + |state| { + // TODO: Enable CREATE/CREATE2 once they are supported + !matches!( + state, + ExecutionState::ErrorInvalidOpcode + | ExecutionState::CREATE + | ExecutionState::CREATE2 + | ExecutionState::SELFDESTRUCT + ) + }, + bytecode_prefix_op_big_rws, + |block, _, step_index| { + let step = &block.txs[0].steps()[step_index]; + let step_next = &block.txs[0].steps()[step_index + 1]; + step_next.rwc.0 - step.rwc.0 + }, + ); +} + +/// Prints the stats of Copy circuit per execution state. +fn copy_states_stats() { + print_circuit_stats_by_states( + |state| { + // TODO: Enable CREATE/CREATE2 once they are supported + matches!( + state, + ExecutionState::RETURNDATACOPY + | ExecutionState::CODECOPY + | ExecutionState::LOG + | ExecutionState::CALLDATACOPY + | ExecutionState::EXTCODECOPY + | ExecutionState::RETURN_REVERT + ) + }, + bytecode_prefix_op_big_rws, + |block, _, _| { + assert!(block.copy_events.len() <= 1); + block + .copy_events + .iter() + .map(|c| c.bytes.len() * 2) + .sum::() + }, + ); +} + +/// This function prints to stdout a table with the top X ExecutionState +/// cell consumers of each EVM Cell type. +fn get_exec_steps_occupancy() { + let mut meta = ConstraintSystem::::default(); + let circuit = EvmCircuit::configure(&mut meta); + + let report = circuit.0.execution.instrument().clone().analyze(); + macro_rules! gen_report { + ($report:expr, $($id:ident, $cols:expr), +) => { + $( + let row_report = report + .iter() + .sorted_by(|a, b| a.$id.utilization.partial_cmp(&b.$id.utilization).unwrap()) + .rev() + .take(10) + .map(|exec| { + vec![ + format!("{:?}", exec.state), + format!("{:?}", exec.$id.available_cells), + format!("{:?}", exec.$id.unused_cells), + format!("{:?}", exec.$id.used_cells), + format!("{:?}", exec.$id.top_height), + format!("{:?}", exec.$id.used_columns), + format!("{:?}", exec.$id.utilization), + ] + }) + .collect::>>(); + + let table = row_report.table().title(vec![ + format!("{:?}", stringify!($id)).cell().bold(true), + format!("total_available_cells").cell().bold(true), + format!("unused_cells").cell().bold(true), + format!("cells").cell().bold(true), + format!("top_height").cell().bold(true), + format!("used columns (Max: {:?})", $cols).cell().bold(true), + format!("Utilization").cell().bold(true), + ]); + print_stdout(table).unwrap(); + )* + }; + } + + gen_report!( + report, + storage_1, + N_PHASE1_COLUMNS, + storage_2, + N_PHASE2_COLUMNS, + storage_perm, + N_COPY_COLUMNS, + byte_lookup, + N_BYTE_LOOKUPS, + fixed_table, + LOOKUP_CONFIG[0].1, + tx_table, + LOOKUP_CONFIG[1].1, + rw_table, + LOOKUP_CONFIG[2].1, + bytecode_table, + LOOKUP_CONFIG[3].1, + block_table, + LOOKUP_CONFIG[4].1, + copy_table, + LOOKUP_CONFIG[5].1, + keccak_table, + LOOKUP_CONFIG[6].1, + exp_table, + LOOKUP_CONFIG[7].1 + ); +} diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index 292c8a2094..342b12a6c4 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -777,45 +777,3 @@ impl SubCircuit for CopyCircuit { config.assign_copy_events(layouter, &self.copy_events, self.max_copy_rows, *challenges) } } - -#[cfg(test)] -mod copy_circuit_stats { - use crate::{ - evm_circuit::step::ExecutionState, - stats::{bytecode_prefix_op_big_rws, print_circuit_stats_by_states}, - }; - - /// Prints the stats of Copy circuit per execution state. See - /// `print_circuit_stats_by_states` for more details. - /// - /// Run with: - /// `cargo test -p zkevm-circuits --release --all-features - /// get_evm_states_stats -- --nocapture --ignored` - #[ignore] - #[test] - fn get_copy_states_stats() { - print_circuit_stats_by_states( - |state| { - // TODO: Enable CREATE/CREATE2 once they are supported - matches!( - state, - ExecutionState::RETURNDATACOPY - | ExecutionState::CODECOPY - | ExecutionState::LOG - | ExecutionState::CALLDATACOPY - | ExecutionState::EXTCODECOPY - | ExecutionState::RETURN_REVERT - ) - }, - bytecode_prefix_op_big_rws, - |block, _, _| { - assert!(block.copy_events.len() <= 1); - block - .copy_events - .iter() - .map(|c| c.bytes.len() * 2) - .sum::() - }, - ); - } -} diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs index 7cf334e891..86d1aad98a 100644 --- a/zkevm-circuits/src/evm_circuit.rs +++ b/zkevm-circuits/src/evm_circuit.rs @@ -8,7 +8,7 @@ use halo2_proofs::{ mod execution; pub mod param; -pub(crate) mod step; +pub mod step; pub mod table; pub(crate) mod util; @@ -39,7 +39,7 @@ use witness::Block; pub struct EvmCircuitConfig { fixed_table: [Column; 4], byte_table: [Column; 1], - pub(crate) execution: Box>, + pub execution: Box>, // External tables tx_table: TxTable, rw_table: RwTable, @@ -74,7 +74,6 @@ impl SubCircuitConfig for EvmCircuitConfig { type ConfigArgs = EvmCircuitConfigArgs; /// Configure EvmCircuitConfig - #[allow(clippy::too_many_arguments)] fn new( meta: &mut ConstraintSystem, Self::ConfigArgs { @@ -440,33 +439,19 @@ impl Circuit for EvmCircuit { #[cfg(test)] mod evm_circuit_stats { use crate::{ - evm_circuit::{ - param::{ - LOOKUP_CONFIG, N_BYTE_LOOKUPS, N_COPY_COLUMNS, N_PHASE1_COLUMNS, N_PHASE2_COLUMNS, - }, - step::ExecutionState, - EvmCircuit, - }, - stats::print_circuit_stats_by_states, + evm_circuit::EvmCircuit, test_util::CircuitTestBuilder, util::{unusable_rows, SubCircuit}, witness::block_convert, }; use bus_mapping::{circuit_input_builder::CircuitsParams, mock::BlockData}; - use cli_table::{print_stdout, Cell, Style, Table}; - use eth_types::{bytecode, evm_types::OpcodeId, geth_types::GethData, ToWord}; - use halo2_proofs::{ - dev::MockProver, - halo2curves::bn256::Fr, - plonk::{Circuit, ConstraintSystem}, - }; - use itertools::Itertools; - use mock::{ - test_ctx::{ - helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, - TestContext, - }, - MOCK_ACCOUNTS, + + use eth_types::{bytecode, geth_types::GethData}; + use halo2_proofs::{self, dev::MockProver, halo2curves::bn256::Fr}; + + use mock::test_ctx::{ + helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, + TestContext, }; #[test] @@ -496,127 +481,6 @@ mod evm_circuit_stats { .run(); } - /// Prints the stats of EVM circuit per execution state. See - /// `print_circuit_stats_by_states` for more details. - /// - /// Run with: - /// `cargo test -p zkevm-circuits --release --all-features - /// get_evm_states_stats -- --nocapture --ignored` - #[ignore] - #[test] - fn get_evm_states_stats() { - print_circuit_stats_by_states( - |state| { - // TODO: Enable CREATE/CREATE2 once they are supported - !matches!( - state, - ExecutionState::ErrorInvalidOpcode - | ExecutionState::CREATE - | ExecutionState::CREATE2 - | ExecutionState::SELFDESTRUCT - ) - }, - |opcode| match opcode { - OpcodeId::RETURNDATACOPY => { - bytecode! { - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH1(0x00) // argsLength - PUSH1(0x00) // argsOffset - PUSH1(0x00) // value - PUSH32(MOCK_ACCOUNTS[3].to_word()) - PUSH32(0x1_0000) // gas - CALL - PUSH2(0x01) // size - PUSH2(0x00) // offset - PUSH2(0x00) // destOffset - } - } - _ => bytecode! { - PUSH2(0x40) - PUSH2(0x50) - }, - }, - |_, state, _| state.get_step_height_option().unwrap(), - ); - } - - /// This function prints to stdout a table with the top X ExecutionState - /// cell consumers of each EVM Cell type. - /// - /// Run with: - /// `cargo test -p zkevm-circuits --release get_exec_steps_occupancy - /// --features test -- --nocapture --ignored` - #[ignore] - #[test] - fn get_exec_steps_occupancy() { - let mut meta = ConstraintSystem::::default(); - let circuit = EvmCircuit::configure(&mut meta); - - let report = circuit.0.execution.instrument().clone().analyze(); - macro_rules! gen_report { - ($report:expr, $($id:ident, $cols:expr), +) => { - $( - let row_report = report - .iter() - .sorted_by(|a, b| a.$id.utilization.partial_cmp(&b.$id.utilization).unwrap()) - .rev() - .take(10) - .map(|exec| { - vec![ - format!("{:?}", exec.state), - format!("{:?}", exec.$id.available_cells), - format!("{:?}", exec.$id.unused_cells), - format!("{:?}", exec.$id.used_cells), - format!("{:?}", exec.$id.top_height), - format!("{:?}", exec.$id.used_columns), - format!("{:?}", exec.$id.utilization), - ] - }) - .collect::>>(); - - let table = row_report.table().title(vec![ - format!("{:?}", stringify!($id)).cell().bold(true), - format!("total_available_cells").cell().bold(true), - format!("unused_cells").cell().bold(true), - format!("cells").cell().bold(true), - format!("top_height").cell().bold(true), - format!("used columns (Max: {:?})", $cols).cell().bold(true), - format!("Utilization").cell().bold(true), - ]); - print_stdout(table).unwrap(); - )* - }; - } - - gen_report!( - report, - storage_1, - N_PHASE1_COLUMNS, - storage_2, - N_PHASE2_COLUMNS, - storage_perm, - N_COPY_COLUMNS, - byte_lookup, - N_BYTE_LOOKUPS, - fixed_table, - LOOKUP_CONFIG[0].1, - tx_table, - LOOKUP_CONFIG[1].1, - rw_table, - LOOKUP_CONFIG[2].1, - bytecode_table, - LOOKUP_CONFIG[3].1, - block_table, - LOOKUP_CONFIG[4].1, - copy_table, - LOOKUP_CONFIG[5].1, - keccak_table, - LOOKUP_CONFIG[6].1, - exp_table, - LOOKUP_CONFIG[7].1 - ); - } #[test] fn variadic_size_check() { let params = CircuitsParams { diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 93668e521d..ff3e48e92d 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -198,7 +198,7 @@ pub(crate) trait ExecutionGadget { } #[derive(Clone, Debug)] -pub(crate) struct ExecutionConfig { +pub struct ExecutionConfig { // EVM Circuit selector, which enables all usable rows. The rows where this selector is // disabled won't verify any constraint (they can be unused rows or rows with blinding // factors). @@ -596,7 +596,7 @@ impl ExecutionConfig { config } - pub(crate) fn instrument(&self) -> &Instrument { + pub fn instrument(&self) -> &Instrument { &self.instrument } diff --git a/zkevm-circuits/src/evm_circuit/param.rs b/zkevm-circuits/src/evm_circuit/param.rs index a2262d21e9..e21530bb9c 100644 --- a/zkevm-circuits/src/evm_circuit/param.rs +++ b/zkevm-circuits/src/evm_circuit/param.rs @@ -16,16 +16,16 @@ pub const MAX_STEP_HEIGHT: usize = 21; pub(crate) const STEP_STATE_HEIGHT: usize = 1; /// Number of Advice Phase2 columns in the EVM circuit -pub(crate) const N_PHASE2_COLUMNS: usize = 4; +pub const N_PHASE2_COLUMNS: usize = 4; /// Number of Advice Phase1 columns in the EVM circuit -pub(crate) const N_PHASE1_COLUMNS: usize = +pub const N_PHASE1_COLUMNS: usize = STEP_WIDTH - EVM_LOOKUP_COLS - N_PHASE2_COLUMNS - N_COPY_COLUMNS - N_BYTE_LOOKUPS; // Number of copy columns -pub(crate) const N_COPY_COLUMNS: usize = 2; +pub const N_COPY_COLUMNS: usize = 2; -pub(crate) const N_BYTE_LOOKUPS: usize = 24; +pub const N_BYTE_LOOKUPS: usize = 24; /// Amount of lookup columns in the EVM circuit dedicated to lookups. pub(crate) const EVM_LOOKUP_COLS: usize = FIXED_TABLE_LOOKUPS @@ -38,7 +38,7 @@ pub(crate) const EVM_LOOKUP_COLS: usize = FIXED_TABLE_LOOKUPS + EXP_TABLE_LOOKUPS; /// Lookups done per row. -pub(crate) const LOOKUP_CONFIG: &[(Table, usize)] = &[ +pub const LOOKUP_CONFIG: &[(Table, usize)] = &[ (Table::Fixed, FIXED_TABLE_LOOKUPS), (Table::Tx, TX_TABLE_LOOKUPS), (Table::Rw, RW_TABLE_LOOKUPS), diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index b0693794da..61323f557a 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -315,7 +315,7 @@ impl ExecutionState { || self.halts_in_exception() } - pub(crate) fn responsible_opcodes(&self) -> Vec { + pub fn responsible_opcodes(&self) -> Vec { if matches!(self, Self::ErrorStack) { return OpcodeId::valid_opcodes() .into_iter() @@ -486,7 +486,7 @@ impl ExecutionState { /// Enum of Responsible opcode mapping to execution state. #[derive(Debug)] -pub(crate) enum ResponsibleOp { +pub enum ResponsibleOp { /// Raw opcode Op(OpcodeId), /// Corresponding to ExecutionState::ErrorStack @@ -501,7 +501,7 @@ impl From for ResponsibleOp { } impl ResponsibleOp { - pub(crate) fn opcode(&self) -> OpcodeId { + pub fn opcode(&self) -> OpcodeId { *match self { ResponsibleOp::Op(opcode) => opcode, ResponsibleOp::InvalidStackPtr(opcode, _) => opcode, diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index e7d5572d00..cc71063003 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -122,7 +122,7 @@ impl FixedTableTag { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] -pub(crate) enum Table { +pub enum Table { Fixed, Tx, Rw, diff --git a/zkevm-circuits/src/evm_circuit/util/instrumentation.rs b/zkevm-circuits/src/evm_circuit/util/instrumentation.rs index 7f03fe6864..eef04dbace 100644 --- a/zkevm-circuits/src/evm_circuit/util/instrumentation.rs +++ b/zkevm-circuits/src/evm_circuit/util/instrumentation.rs @@ -12,7 +12,7 @@ type ColumnSize = (usize, usize, usize); /// Instrument captures metrics during the compilation of a circuit. #[derive(Clone, Debug, Default)] -pub(crate) struct Instrument { +pub struct Instrument { // States -> Cell Types -> (width, height, num_cells) states: Vec<(ExecutionState, StepSize)>, } @@ -38,7 +38,7 @@ impl Instrument { /// Dissasembles the instrumentation data and returns a collection of /// `ExecStateReport`s. One for each EVM `ExecutionState`. - pub(crate) fn analyze(&self) -> Vec { + pub fn analyze(&self) -> Vec { let mut report_collection = vec![]; for (state, sizes) in &self.states { // Create a state report @@ -111,20 +111,20 @@ impl Instrument { /// Struct which contains a Cost/ColumnType report for a particular EVM /// `ExecutionStep`. #[derive(Clone, Debug, Default)] -pub(crate) struct ExecStateReport { - pub(crate) state: ExecutionState, - pub(crate) storage_1: StateReportRow, - pub(crate) storage_2: StateReportRow, - pub(crate) storage_perm: StateReportRow, - pub(crate) byte_lookup: StateReportRow, - pub(crate) fixed_table: StateReportRow, - pub(crate) tx_table: StateReportRow, - pub(crate) rw_table: StateReportRow, - pub(crate) bytecode_table: StateReportRow, - pub(crate) block_table: StateReportRow, - pub(crate) copy_table: StateReportRow, - pub(crate) keccak_table: StateReportRow, - pub(crate) exp_table: StateReportRow, +pub struct ExecStateReport { + pub state: ExecutionState, + pub storage_1: StateReportRow, + pub storage_2: StateReportRow, + pub storage_perm: StateReportRow, + pub byte_lookup: StateReportRow, + pub fixed_table: StateReportRow, + pub tx_table: StateReportRow, + pub rw_table: StateReportRow, + pub bytecode_table: StateReportRow, + pub block_table: StateReportRow, + pub copy_table: StateReportRow, + pub keccak_table: StateReportRow, + pub exp_table: StateReportRow, } impl From for ExecStateReport { @@ -148,17 +148,17 @@ impl From<&ExecutionState> for ExecStateReport { /// Struct that contains all of the measurament values required to evaluate the /// costs of a particular `ColumnType` of an `ExecStateReport` #[derive(Debug, Clone, Default)] -pub(crate) struct StateReportRow { +pub struct StateReportRow { // Given a rigion of x columns and y rows, we have x * y cells available for computation. - pub(crate) available_cells: usize, + pub available_cells: usize, // The cells not used in the computation in the x*y region. These are the wasted cells. - pub(crate) unused_cells: usize, + pub unused_cells: usize, // The cells used in the computation in the x*y region. - pub(crate) used_cells: usize, + pub used_cells: usize, // The largest y within all the `CellType`. - pub(crate) top_height: usize, + pub top_height: usize, // If we fully utilize y, how large is the x really needed? - pub(crate) used_columns: usize, + pub used_columns: usize, // The percentage of cells used in computation in the x * y region. - pub(crate) utilization: f64, + pub utilization: f64, } diff --git a/zkevm-circuits/src/lib.rs b/zkevm-circuits/src/lib.rs index 20777ec3f5..a5eb0ad76f 100644 --- a/zkevm-circuits/src/lib.rs +++ b/zkevm-circuits/src/lib.rs @@ -31,9 +31,6 @@ pub mod table; #[cfg(any(feature = "test", test))] pub mod test_util; -#[cfg(any(feature = "test", test))] -mod stats; - pub mod tx_circuit; pub mod util; pub mod witness; diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index 0270ca098d..e07415e288 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -591,40 +591,3 @@ fn queries(meta: &mut VirtualCells<'_, F>, c: &StateCircuitConfig) state_root_prev: meta.query_advice(c.state_root, Rotation::prev()), } } - -#[cfg(test)] -mod state_circuit_stats { - use crate::{ - evm_circuit::step::ExecutionState, - stats::{bytecode_prefix_op_big_rws, print_circuit_stats_by_states}, - }; - - /// Prints the stats of State circuit per execution state. See - /// `print_circuit_stats_by_states` for more details. - /// - /// Run with: - /// `cargo test -p zkevm-circuits --release --all-features - /// get_state_states_stats -- --nocapture --ignored` - #[ignore] - #[test] - pub fn get_state_states_stats() { - print_circuit_stats_by_states( - |state| { - // TODO: Enable CREATE/CREATE2 once they are supported - !matches!( - state, - ExecutionState::ErrorInvalidOpcode - | ExecutionState::CREATE - | ExecutionState::CREATE2 - | ExecutionState::SELFDESTRUCT - ) - }, - bytecode_prefix_op_big_rws, - |block, _, step_index| { - let step = &block.txs[0].steps()[step_index]; - let step_next = &block.txs[0].steps()[step_index + 1]; - step_next.rwc.0 - step.rwc.0 - }, - ); - } -} From ef1392700969b048ba43f23cbb9a02f34372d817 Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Tue, 16 May 2023 21:43:12 +0800 Subject: [PATCH 043/102] Rm dead code except of zkevm circuits (#1408) ### Description We remove `#![allow(dead_code)]` everywhere in the codebases other than `zkevm-circuits`. This PR should be merged after #1407 ### Issue Link No issue yet ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - Removed `#![allow(dead_code)]` everywhere other than `zkevm-circuits`. - Make test utility functions like `Block::get_test_degree` and `Sha3CodeGen` public functions so that they don't cause `cargo build -p zkevm-circuits` to fail. This might come with the cost of extra compilation time. - Refactor `gen_sha3_code` into `Sha3CodeGen` so that we don't have to import `MemoryKind` to use it. --- .../src/circuit_input_builder/block.rs | 4 +- .../src/circuit_input_builder/tracer_tests.rs | 11 - bus-mapping/src/evm.rs | 3 +- bus-mapping/src/evm/opcodes.rs | 3 +- bus-mapping/src/evm/opcodes/callop.rs | 3 +- .../src/evm/opcodes/memory_expansion_test.rs | 8 - bus-mapping/src/evm/opcodes/sha3.rs | 163 +++++---- bus-mapping/src/lib.rs | 2 - eth-types/src/lib.rs | 2 - gadgets/src/evm_word.rs | 276 ---------------- gadgets/src/lib.rs | 21 +- gadgets/src/monotone.rs | 311 ------------------ testool/src/statetest/json.rs | 14 +- zkevm-circuits/src/copy_circuit.rs | 2 +- zkevm-circuits/src/copy_circuit/test.rs | 6 +- .../src/evm_circuit/execution/sha3.rs | 27 +- zkevm-circuits/src/witness/block.rs | 21 +- 17 files changed, 130 insertions(+), 747 deletions(-) delete mode 100644 gadgets/src/evm_word.rs delete mode 100644 gadgets/src/monotone.rs diff --git a/bus-mapping/src/circuit_input_builder/block.rs b/bus-mapping/src/circuit_input_builder/block.rs index cf3f62070d..650c7344bc 100644 --- a/bus-mapping/src/circuit_input_builder/block.rs +++ b/bus-mapping/src/circuit_input_builder/block.rs @@ -7,7 +7,7 @@ use crate::{ operation::{OperationContainer, RWCounter}, Error, }; -use eth_types::{evm_unimplemented, Address, Hash, Word}; +use eth_types::{evm_unimplemented, Address, Word}; use std::collections::HashMap; /// Context of a [`Block`] which can mutate in a [`Transaction`]. @@ -86,7 +86,6 @@ pub struct Block { pub sha3_inputs: Vec>, /// Exponentiation events in the block. pub exp_events: Vec, - code: HashMap>, /// Circuits Setup Paramteres pub circuits_params: CircuitsParams, /// Original block from geth @@ -139,7 +138,6 @@ impl Block { }, copy_events: Vec::new(), exp_events: Vec::new(), - code: HashMap::new(), sha3_inputs: Vec::new(), circuits_params, eth_block: eth_block.clone(), diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index 6fe834a612..ebd4fac6cd 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -6,7 +6,6 @@ use crate::{ GETH_ERR_GAS_UINT_OVERFLOW, GETH_ERR_OUT_OF_GAS, GETH_ERR_STACK_OVERFLOW, GETH_ERR_STACK_UNDERFLOW, }, - operation::RWCounter, state_db::Account, }; use eth_types::{ @@ -31,7 +30,6 @@ struct CircuitInputBuilderTx { builder: CircuitInputBuilder, tx: Transaction, pub(crate) tx_ctx: TransactionContext, - step: ExecStep, } impl CircuitInputBuilderTx { @@ -53,19 +51,10 @@ impl CircuitInputBuilderTx { ) .unwrap(); - let prev_log_id = if tx.is_steps_empty() { - 0 - } else { - tx.last_step().log_id - }; - - let call_ctx = tx_ctx.call_ctx().unwrap(); - let exec_step = ExecStep::new(geth_step, call_ctx, RWCounter::new(), 0, prev_log_id); Self { builder, tx, tx_ctx, - step: exec_step, } } diff --git a/bus-mapping/src/evm.rs b/bus-mapping/src/evm.rs index 319040887a..39cd478c9f 100644 --- a/bus-mapping/src/evm.rs +++ b/bus-mapping/src/evm.rs @@ -5,5 +5,4 @@ pub(crate) mod opcodes; pub use eth_types::evm_types::opcode_ids::OpcodeId; pub use opcodes::Opcode; -#[cfg(any(feature = "test", test))] -pub use opcodes::{gen_sha3_code, MemoryKind}; +pub use opcodes::Sha3CodeGen; diff --git a/bus-mapping/src/evm/opcodes.rs b/bus-mapping/src/evm/opcodes.rs index db310525cb..781d724882 100644 --- a/bus-mapping/src/evm/opcodes.rs +++ b/bus-mapping/src/evm/opcodes.rs @@ -9,8 +9,7 @@ use crate::{ use core::fmt::Debug; use eth_types::{evm_unimplemented, GethExecStep, ToAddress}; -#[cfg(any(feature = "test", test))] -pub use self::sha3::sha3_tests::{gen_sha3_code, MemoryKind}; +pub use self::sha3::Sha3CodeGen; mod address; mod balance; diff --git a/bus-mapping/src/evm/opcodes/callop.rs b/bus-mapping/src/evm/opcodes/callop.rs index c63c70e7dc..1786bf2f7b 100644 --- a/bus-mapping/src/evm/opcodes/callop.rs +++ b/bus-mapping/src/evm/opcodes/callop.rs @@ -742,7 +742,8 @@ mod tests { assert_eq!( *stack_value, step.stack.nth_last(offset).expect("stack value not found"), - "stack output mismatch" + "stack output mismatch {}", + test_call.name ); } } diff --git a/bus-mapping/src/evm/opcodes/memory_expansion_test.rs b/bus-mapping/src/evm/opcodes/memory_expansion_test.rs index 36eb5ad5a0..48cdcbc2d2 100644 --- a/bus-mapping/src/evm/opcodes/memory_expansion_test.rs +++ b/bus-mapping/src/evm/opcodes/memory_expansion_test.rs @@ -7,14 +7,6 @@ use mock::{ TestContext, }; -fn might_neg_index(index: isize, len: usize) -> usize { - if index < 0 { - (len as isize + index) as usize - } else { - index as usize - } -} - fn assert_expanded(_traces: &[GethExecStep], _before: isize, _after: isize) { // FIXME: memory is removed // let traces_len = traces.len(); diff --git a/bus-mapping/src/evm/opcodes/sha3.rs b/bus-mapping/src/evm/opcodes/sha3.rs index 2179860d18..65f4408817 100644 --- a/bus-mapping/src/evm/opcodes/sha3.rs +++ b/bus-mapping/src/evm/opcodes/sha3.rs @@ -1,13 +1,13 @@ +use super::Opcode; use crate::{ circuit_input_builder::{ CircuitInputStateRef, CopyDataType, CopyEvent, ExecStep, NumberOrHash, }, Error, }; -use eth_types::{GethExecStep, Word, U256}; +use eth_types::{bytecode, Bytecode, GethExecStep, Word, U256}; use ethers_core::utils::keccak256; - -use super::Opcode; +use rand::{rngs::ThreadRng, Rng}; #[derive(Clone, Copy, Debug)] pub(crate) struct Sha3; @@ -82,49 +82,78 @@ impl Opcode for Sha3 { } } -#[cfg(any(feature = "test", test))] -pub mod sha3_tests { - use eth_types::{bytecode, evm_types::OpcodeId, geth_types::GethData, Bytecode, Word}; - use ethers_core::utils::keccak256; - use mock::{ - test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, - TestContext, - }; - use rand::{random, Rng}; - - use crate::{ - circuit_input_builder::{CircuitsParams, ExecState}, - mock::BlockData, - operation::{MemoryOp, StackOp, RW}, - }; - +/// Generate Sha3 opcode +pub struct Sha3CodeGen { + /// The offset + pub offset: usize, + /// The size + pub size: usize, + data_len: usize, + rng: ThreadRng, +} +impl Sha3CodeGen { + /// Construct with memory less than size + pub fn mem_lt_size(offset: usize, size: usize) -> Self { + let mut rng = rand::thread_rng(); + let data_len = offset + + if size.gt(&0) { + rng.gen_range(0..size) + } else { + 0 + }; + Self { + offset, + size, + data_len, + rng, + } + } + /// Construct with memory equal to size + pub fn mem_eq_size(offset: usize, size: usize) -> Self { + let data_len = offset + size; + Self { + offset, + size, + data_len, + rng: rand::thread_rng(), + } + } + /// Construct with memory greater than size + pub fn mem_gt_size(offset: usize, size: usize) -> Self { + let mut rng = rand::thread_rng(); + let data_len = offset + + size + + if size.gt(&0) { + rng.gen_range(0..size) + } else { + 0 + }; + Self { + offset, + size, + data_len, + rng, + } + } + /// Construct with empty memory + pub fn mem_empty(offset: usize, size: usize) -> Self { + Self { + offset, + size, + data_len: 0, + rng: rand::thread_rng(), + } + } + fn rand_bytes(&mut self) -> Vec { + (0..self.data_len) + .map(|_| self.rng.gen()) + .collect::>() + } /// Generate bytecode for SHA3 opcode after having populated sufficient /// memory given the offset and size arguments for SHA3. - pub fn gen_sha3_code(offset: usize, size: usize, mem_kind: MemoryKind) -> (Bytecode, Vec) { - let mut rng = rand::thread_rng(); - let data_len = match mem_kind { - MemoryKind::LessThanSize => { - offset - + if size.gt(&0) { - rng.gen_range(0..size) - } else { - 0 - } - } - MemoryKind::EqualToSize => offset + size, - MemoryKind::MoreThanSize => { - offset - + size - + if size.gt(&0) { - rng.gen_range(0..size) - } else { - 0 - } - } - MemoryKind::Empty => 0, - }; - let data = rand_bytes(data_len); - let mut memory = Vec::with_capacity(data_len); + pub fn gen_sha3_code(&mut self) -> (Bytecode, Vec) { + let data = self.rand_bytes(); + let mut memory = Vec::with_capacity(self.data_len); // add opcodes to populate memory in the current context. let mut code = Bytecode::default(); @@ -142,33 +171,35 @@ pub mod sha3_tests { } // append SHA3 related opcodes at the tail end. let code_tail = bytecode! { - PUSH32(size) - PUSH32(offset) + PUSH32(self.size) + PUSH32(self.offset) SHA3 STOP }; code.append(&code_tail); (code, memory) } +} - /// Memory of a context with respect to the input size to SHA3. - pub enum MemoryKind { - /// Variant defining empty memory. - Empty, - /// Variant defining memory length being less than size. - LessThanSize, - /// Variant defining memory length being equal to size. - EqualToSize, - /// Variant defining memory length being more than size. - MoreThanSize, - } +#[cfg(test)] +pub(crate) mod sha3_tests { + use super::Sha3CodeGen; + use eth_types::{evm_types::OpcodeId, geth_types::GethData, Word}; + use ethers_core::utils::keccak256; + use mock::{ + test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, + TestContext, + }; - fn rand_bytes(size: usize) -> Vec { - (0..size).map(|_| random()).collect::>() - } + use crate::{ + circuit_input_builder::{CircuitsParams, ExecState}, + mock::BlockData, + operation::{MemoryOp, StackOp, RW}, + }; - fn test_ok(offset: usize, size: usize, mem_kind: MemoryKind) { - let (code, memory) = gen_sha3_code(offset, size, mem_kind); + fn test_ok(mut gen: Sha3CodeGen) { + let (code, memory) = gen.gen_sha3_code(); + let (size, offset) = (gen.size, gen.offset); let memory_len = memory.len(); // The memory that is hashed. @@ -265,9 +296,9 @@ pub mod sha3_tests { #[test] fn sha3_opcode_ok() { - test_ok(0x10, 0x32, MemoryKind::Empty); - test_ok(0x34, 0x44, MemoryKind::LessThanSize); - test_ok(0x222, 0x111, MemoryKind::EqualToSize); - test_ok(0x20, 0x30, MemoryKind::MoreThanSize); + test_ok(Sha3CodeGen::mem_empty(0x10, 0x32)); + test_ok(Sha3CodeGen::mem_lt_size(0x34, 0x44)); + test_ok(Sha3CodeGen::mem_eq_size(0x222, 0x111)); + test_ok(Sha3CodeGen::mem_gt_size(0x20, 0x30)); } } diff --git a/bus-mapping/src/lib.rs b/bus-mapping/src/lib.rs index 131cf5ebe8..5a068e21f8 100644 --- a/bus-mapping/src/lib.rs +++ b/bus-mapping/src/lib.rs @@ -213,8 +213,6 @@ //! See: #![cfg_attr(docsrs, feature(doc_cfg))] -// Temporary until we have more of the crate implemented. -#![allow(dead_code)] // We want to have UPPERCASE idents sometimes. #![allow(non_snake_case)] // Catch documentation errors caused by code changes. diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index bbe3ab9eb1..21e2486f61 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -1,8 +1,6 @@ //! Ethereum and Evm types used to deserialize responses from web3 / geth. #![cfg_attr(docsrs, feature(doc_cfg))] -// Temporary until we have more of the crate implemented. -#![allow(dead_code)] // We want to have UPPERCASE idents sometimes. #![allow(non_snake_case)] // Catch documentation errors caused by code changes. diff --git a/gadgets/src/evm_word.rs b/gadgets/src/evm_word.rs deleted file mode 100644 index 3245bd327f..0000000000 --- a/gadgets/src/evm_word.rs +++ /dev/null @@ -1,276 +0,0 @@ -//! An EVM word (256 bits) is represented as a linear combination of 32 bytes: -//! `encode(word) = b_0 + r * b_1 + ... + r^{31} * b_{31}`, -//! where `word` is a 256-bit word, b_i's are bytes, and `r` is a random factor. -//! This helper returns an expression of `encode(word)`. -//! -//! In the zkevm circuit, this `encode(word)` expression will not be directly -//! looked up. Instead, it will be folded into the bus mapping lookup. - -use crate::Variable; -use digest::{FixedOutput, Input}; -use eth_types::Field; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector}, - poly::Rotation, -}; -use sha3::{Digest, Keccak256}; - -#[cfg(test)] -use halo2_proofs::circuit::Layouter; - -// TODO: Move into crate-level `constants` file. -/// r = hash([0, 1, ..., 255]) -pub fn r() -> F { - let mut hasher = Keccak256::new(); - for byte in 0..=u8::MAX { - hasher.process(&[byte]); - } - let mut r = [0; 64]; - r[..32].copy_from_slice(hasher.fixed_result().as_slice()); - F::from_uniform_bytes(&r) -} - -/// Returns encoding of big-endian representation of a 256-bit word. -pub fn encode(vals: impl Iterator, r: F) -> F { - vals.fold(F::ZERO, |acc, val| { - let byte = F::from(val as u64); - acc * r + byte - }) -} - -/// A 256-bit word represented in the circuit as 32 bytes. -pub struct Word([Variable; 32]); - -#[allow(dead_code)] -/// Configuration structure used to constraint. generate and assign an EVM Word -/// inside a circuit. -#[derive(Clone, Debug)] -pub struct WordConfig { - /// Randomness used to compress the word encoding. - r: F, - /// Selector to toggle the word encoding gate. - // TODO: This may be replaced by a synthetic selector. - q_encode: Selector, - /// Advice columns used to witness the byte representation of the word. - bytes: [Column; 32], - /// Fixed column containing all possible 8-bit values. This is used in - /// a lookup argument to range-constrain each byte. - byte_lookup: Column, - /// Expression representing `encode(word)`. - encode_word_expr: Expression, -} - -impl WordConfig { - /// Sets up the configuration of the config by creating the required columns - /// & selectors and defining the constraints that take part when using a - /// Word. - pub fn configure( - meta: &mut ConstraintSystem, - r: F, - q_encode: Selector, - bytes: [Column; 32], - byte_lookup: Column, - ) -> Self { - // Expression representing `encode(word)`. - let mut encode_word_expr = Expression::Constant(F::ZERO); - - // Lookup each byte in the witnessed word representation to - // range-constrain it to 8 bits. - for byte in bytes.iter().rev() { - meta.lookup_any("Word byte for range", |meta| { - let q_encode = meta.query_selector(q_encode); - let r = Expression::Constant(r); - let byte = meta.query_advice(*byte, Rotation::cur()); - let byte_lookup = meta.query_fixed(byte_lookup, Rotation::cur()); - - // Update encode_word_expr. - encode_word_expr = encode_word_expr.clone() * r + byte.clone(); - - vec![(q_encode * byte, byte_lookup)] - }); - } - - Self { - r, - q_encode, - bytes, - byte_lookup, - encode_word_expr, - } - } - - /// Loads the 8-bit lookup table. - /// NB: This is only used in tests, since the zkevm circuit will load a - /// global 8-bit table. - #[cfg(test)] - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "8-bit table", - |mut meta| { - for byte in 0..=u8::MAX { - meta.assign_fixed( - || format!("load {}", byte), - self.byte_lookup, - byte.into(), - || Value::known(F::from(byte as u64)), - )?; - } - - Ok(()) - }, - ) - } - - /// Assigns the byte decomposition of a word to the `bytes` advice columns. - pub fn assign_word( - &self, - region: &mut Region<'_, F>, - offset: usize, - word: [Value; 32], - ) -> Result, Error> { - let mut bytes: Vec> = Vec::with_capacity(32); - - for (idx, (byte, column)) in word.iter().zip(self.bytes.iter()).enumerate() { - // TODO: We will likely enable this selector outside of the helper. - self.q_encode.enable(region, offset)?; - - let byte_field_elem = byte.map(|byte| F::from(byte as u64)); - let cell = region.assign_advice( - || format!("assign byte {}", idx), - *column, - offset, - || byte_field_elem, - )?; - - bytes.push(Variable::new(cell, *byte)); - } - - Ok(Word(bytes.try_into().unwrap())) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use halo2_proofs::{ - arithmetic::Field as Halo2Field, - circuit::SimpleFloorPlanner, - dev::{FailureLocation, MockProver, VerifyFailure}, - halo2curves::{bn256::Fr as Fp, group::ff::PrimeField}, - plonk::{Circuit, Instance}, - }; - use rand::SeedableRng; - use rand_xorshift::XorShiftRng; - use std::marker::PhantomData; - - #[test] - fn evm_word() { - #[derive(Default)] - struct MyCircuit { - word: [Value; 32], - _marker: PhantomData, - } - - impl Circuit for MyCircuit { - // Introduce an additional instance column here to test lookups - // with public inputs. This is analogous to the bus mapping - // commitment which will be provided as public inputs. - type Config = (WordConfig, Column); - type FloorPlanner = SimpleFloorPlanner; - type Params = (); - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let r = r(); - - let q_encode = meta.complex_selector(); - - let bytes: [Column; 32] = (0..32) - .map(|_| meta.advice_column()) - .collect::>() - .try_into() - .unwrap(); - let byte_lookup = meta.fixed_column(); - - let config = WordConfig::configure(meta, r, q_encode, bytes, byte_lookup); - - let pub_inputs = meta.instance_column(); - - // Make sure each encoded word has been committed to in the - // public inputs. - meta.lookup_any("Encoded word / Pub inputs", |meta| { - let q_encode = meta.query_selector(q_encode); - let pub_inputs = meta.query_instance(pub_inputs, Rotation::cur()); - - let encode_word = config.clone().encode_word_expr; - - vec![(q_encode * encode_word, pub_inputs)] - }); - - (config, pub_inputs) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - config.0.load(&mut layouter)?; - - layouter.assign_region( - || "assign word", - |mut region| { - let offset = 0; - config.0.assign_word(&mut region, offset, self.word) - }, - )?; - - Ok(()) - } - } - - { - let rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - let word = Fp::random(rng); - let circuit = MyCircuit:: { - word: word - .to_repr() - .iter() - .map(|b| Value::known(*b)) - .collect::>() - .try_into() - .unwrap(), - _marker: PhantomData, - }; - - // Test without public inputs - let prover = MockProver::::run(9, &circuit, vec![vec![]]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - name: "Encoded word / Pub inputs".to_string(), - lookup_index: 32, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from(( - 1, - "assign word".to_string() - )), - offset: 0 - } - }]) - ); - - // Calculate word commitment and use it as public input. - let encoded: Fp = encode(word.to_repr().iter().rev().cloned(), r()); - let prover = MockProver::::run(9, &circuit, vec![vec![encoded]]).unwrap(); - prover.assert_satisfied_par() - } - } -} diff --git a/gadgets/src/lib.rs b/gadgets/src/lib.rs index 3ef7fae9a1..a7150262ee 100644 --- a/gadgets/src/lib.rs +++ b/gadgets/src/lib.rs @@ -13,32 +13,13 @@ pub mod batched_is_zero; pub mod binary_number; -pub mod evm_word; pub mod is_zero; pub mod less_than; -pub mod monotone; pub mod mul_add; pub mod util; use eth_types::Field; -use halo2_proofs::{ - circuit::{AssignedCell, Value}, - plonk::Expression, -}; - -#[allow(dead_code)] -/// An assigned cell in the circuit. -#[derive(Clone, Debug)] -pub struct Variable { - assig_cell: AssignedCell, - value: Value, -} - -impl Variable { - pub(crate) fn new(assig_cell: AssignedCell, value: Value) -> Self { - Self { assig_cell, value } - } -} +use halo2_proofs::plonk::Expression; /// Restrict an expression to be a boolean. pub fn bool_check(value: Expression) -> Expression { diff --git a/gadgets/src/monotone.rs b/gadgets/src/monotone.rs deleted file mode 100644 index 3d37a4366f..0000000000 --- a/gadgets/src/monotone.rs +++ /dev/null @@ -1,311 +0,0 @@ -//! # Monotone mod -//! Monotone gadget helps to check if an advice column is monotonically -//! increasing within a range. With strict enabled, it disallows equality of two -//! cell. -use eth_types::Field; -use halo2_proofs::{ - circuit::{Chip, Layouter, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, - poly::Rotation, -}; -use std::{marker::PhantomData, u64}; - -#[allow(dead_code)] -#[derive(Clone, Debug)] -pub(crate) struct MonotoneConfig { - range_table: Column, - value: Column, -} - -/// MonotoneChip helps to check if an advice column is monotonically increasing -/// within a range. With strict enabled, it disallows equality of two cell. -pub(crate) struct MonotoneChip { - config: MonotoneConfig, - _marker: PhantomData, -} - -#[allow(dead_code)] -impl - MonotoneChip -{ - /// configure which column should be check. q_enable here as a fn is - /// flexible for synthetic selector instead of a fixed one. - pub fn configure( - meta: &mut ConstraintSystem, - q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression, - value: Column, - ) -> MonotoneConfig { - let range_table = meta.fixed_column(); - - let config = MonotoneConfig { range_table, value }; - - meta.lookup_any("Range check", |meta| { - let q_enable = q_enable(meta); - let range_table = meta.query_fixed(config.range_table, Rotation::cur()); - let value_diff = { - let value_cur = meta.query_advice(value, Rotation::cur()); - let value_prev = meta.query_advice(value, Rotation::prev()); - if INCR { - value_cur - value_prev - } else { - value_prev - value_cur - } - }; - - // If strict monotone, we subtract diff by one - // to make sure zero lookup fail - let min_diff = Expression::Constant(F::from(STRICT as u64)); - - vec![(q_enable * (value_diff - min_diff), range_table)] - }); - - config - } - - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "range_table", - |mut meta| { - let max = RANGE - STRICT as usize; - - for idx in 0..=max { - meta.assign_fixed( - || "range_table_value", - self.config.range_table, - idx, - || Value::known(F::from(idx as u64)), - )?; - } - - Ok(()) - }, - ) - } - - pub fn construct(config: MonotoneConfig) -> Self { - Self { - config, - _marker: PhantomData, - } - } -} - -impl Chip - for MonotoneChip -{ - type Config = MonotoneConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -#[cfg(test)] -mod test { - use super::*; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::{ - FailureLocation, MockProver, - VerifyFailure::{self, Lookup}, - }, - halo2curves::bn256::Fr as Fp, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Selector}, - }; - use std::marker::PhantomData; - - #[derive(Clone, Debug)] - struct TestCircuitConfig { - q_enable: Selector, - value: Column, - mono_incr: MonotoneConfig, - } - - #[derive(Default)] - struct TestCircuit { - values: Option>, - _marker: PhantomData, - } - - impl Circuit - for TestCircuit - { - type Config = TestCircuitConfig; - type FloorPlanner = SimpleFloorPlanner; - type Params = (); - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let q_enable = meta.complex_selector(); - let value = meta.advice_column(); - - let mono_incr = MonotoneChip::::configure( - meta, - |meta| meta.query_selector(q_enable), - value, - ); - - Self::Config { - q_enable, - value, - mono_incr, - } - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let monotone_chip = - MonotoneChip::::construct(config.mono_incr.clone()); - - monotone_chip.load(&mut layouter)?; - - let values: Vec<_> = self - .values - .as_ref() - .map(|values| values.iter().map(|value| F::from(*value)).collect()) - .ok_or(Error::Synthesis)?; - - layouter.assign_region( - || "witness", - |mut region| { - for (idx, value) in values.iter().enumerate() { - region.assign_advice( - || "value", - config.value, - idx, - || Value::known(*value), - )?; - if idx > 0 { - config.q_enable.enable(&mut region, idx)?; - } - } - - Ok(()) - }, - ) - } - } - - macro_rules! gen_try_test_circuit { - ($range:expr, $incr:expr, $strict:expr) => { - fn try_test_circuit(values: Vec, result: Result<(), Vec>) { - let circuit = TestCircuit:: { - values: Some(values), - _marker: PhantomData, - }; - let prover = MockProver::::run( - usize::BITS - ($range as usize).leading_zeros(), - &circuit, - vec![], - ) - .unwrap(); - if result.is_err() { - assert_eq!(prover.verify_par(), result) - } else { - prover.assert_satisfied_par() - } - } - }; - } - - #[test] - fn strict_monotonically_increasing() { - gen_try_test_circuit!(100, true, true); - - // strict monotone in range (ok) - try_test_circuit(vec![1, 2, 3, 4, 104], Ok(())); - try_test_circuit(vec![1001, 1002, 1003, 1004, 1104], Ok(())); - // non-strict monotone in range (error) - try_test_circuit( - vec![1, 2, 2, 4, 4], - Err(vec![ - Lookup { - name: "Range check".to_string(), - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 2, - }, - }, - Lookup { - name: "Range check".to_string(), - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 4, - }, - }, - ]), - ); - // out of range (error) - try_test_circuit( - vec![1, 2, 3, 4, 105], - Err(vec![Lookup { - name: "Range check".to_string(), - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 4, - }, - }]), - ); - // not monotone (error) - try_test_circuit( - vec![1, 2, 3, 103, 4], - Err(vec![Lookup { - name: "Range check".to_string(), - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 4, - }, - }]), - ); - } - - #[test] - fn non_strict_monotonically_increasing() { - gen_try_test_circuit!(100, true, false); - - // strict monotone in range (ok) - try_test_circuit(vec![1, 2, 3, 4, 104], Ok(())); - try_test_circuit(vec![1001, 1002, 1003, 1004, 1104], Ok(())); - // non-strict monotone in range (ok) - try_test_circuit(vec![1, 2, 2, 4, 4], Ok(())); - // out of range (error) - try_test_circuit( - vec![1, 2, 3, 4, 105], - Err(vec![Lookup { - name: "Range check".to_string(), - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 4, - }, - }]), - ); - // not monotone (error) - try_test_circuit( - vec![1, 2, 3, 103, 4], - Err(vec![Lookup { - name: "Range check".to_string(), - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 4, - }, - }]), - ); - } -} diff --git a/testool/src/statetest/json.rs b/testool/src/statetest/json.rs index a083077a8f..14c042720f 100644 --- a/testool/src/statetest/json.rs +++ b/testool/src/statetest/json.rs @@ -1,16 +1,13 @@ -#![allow(dead_code, unused_imports)] - use super::{ parse, spec::{AccountMatch, Env, StateTest}, }; -use crate::{abi, compiler::Compiler, utils::MainnetFork}; -use anyhow::{bail, Context, Result}; -use eth_types::{evm_types::OpcodeId, geth_types::Account, Address, Bytes, H256, U256}; +use crate::{compiler::Compiler, utils::MainnetFork}; +use anyhow::{bail, Result}; +use eth_types::{geth_types::Account, Address, U256}; use ethers_core::{k256::ecdsa::SigningKey, utils::secret_key_to_address}; use serde::Deserialize; -use std::{collections::HashMap, convert::TryInto, ops::RangeBounds, str::FromStr}; -use yaml_rust::Yaml; +use std::collections::HashMap; #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] @@ -36,7 +33,6 @@ struct AccountPost { code: Option, nonce: Option, storage: Option>, - shouldnotexist: Option, } #[derive(Debug, Clone, Deserialize)] @@ -298,6 +294,8 @@ impl<'a> JsonStateTestBuilder<'a> { #[cfg(test)] mod test { use super::*; + use eth_types::{Bytes, H256}; + use std::{collections::HashMap, str::FromStr}; const JSON: &str = r#" { diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index 342b12a6c4..0817773493 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -5,7 +5,7 @@ pub(crate) mod util; #[cfg(any(feature = "test", test, feature = "test-circuits"))] mod dev; -#[cfg(any(feature = "test", test))] +#[cfg(test)] mod test; #[cfg(any(feature = "test", test, feature = "test-circuits"))] pub use dev::CopyCircuit as TestCopyCircuit; diff --git a/zkevm-circuits/src/copy_circuit/test.rs b/zkevm-circuits/src/copy_circuit/test.rs index 88fdd3e170..b60b965c9a 100644 --- a/zkevm-circuits/src/copy_circuit/test.rs +++ b/zkevm-circuits/src/copy_circuit/test.rs @@ -1,5 +1,3 @@ -#![allow(unused_imports)] - use crate::{ copy_circuit::*, evm_circuit::{test::rand_bytes, witness::block_convert}, @@ -8,7 +6,7 @@ use crate::{ }; use bus_mapping::{ circuit_input_builder::{CircuitInputBuilder, CircuitsParams}, - evm::{gen_sha3_code, MemoryKind}, + evm::Sha3CodeGen, mock::BlockData, }; use eth_types::{bytecode, geth_types::GethData, ToWord, Word}; @@ -153,7 +151,7 @@ fn gen_extcodecopy_data() -> CircuitInputBuilder { } fn gen_sha3_data() -> CircuitInputBuilder { - let (code, _) = gen_sha3_code(0x20, 0x200, MemoryKind::EqualToSize); + let (code, _) = Sha3CodeGen::mem_eq_size(0x20, 0x200).gen_sha3_code(); let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(); let block: GethData = test_ctx.into(); let mut builder = BlockData::new_from_geth_data_with_params( diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index 63191e4e79..6d948f1880 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -157,14 +157,11 @@ impl ExecutionGadget for Sha3Gadget { #[cfg(test)] mod tests { use crate::test_util::CircuitTestBuilder; - use bus_mapping::{ - circuit_input_builder::CircuitsParams, - evm::{gen_sha3_code, MemoryKind}, - }; + use bus_mapping::{circuit_input_builder::CircuitsParams, evm::Sha3CodeGen}; use mock::TestContext; - fn test_ok(offset: usize, size: usize, mem_kind: MemoryKind) { - let (code, _) = gen_sha3_code(offset, size, mem_kind); + fn test_ok(mut gen: Sha3CodeGen) { + let (code, _) = gen.gen_sha3_code(); CircuitTestBuilder::new_from_test_ctx( TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(), ) @@ -177,22 +174,22 @@ mod tests { #[test] fn sha3_gadget_zero_length() { - test_ok(0x20, 0x00, MemoryKind::MoreThanSize); + test_ok(Sha3CodeGen::mem_gt_size(0x20, 0x00)); } #[test] fn sha3_gadget_simple() { - test_ok(0x00, 0x08, MemoryKind::Empty); - test_ok(0x10, 0x10, MemoryKind::LessThanSize); - test_ok(0x24, 0x16, MemoryKind::EqualToSize); - test_ok(0x32, 0x78, MemoryKind::MoreThanSize); + test_ok(Sha3CodeGen::mem_empty(0x00, 0x08)); + test_ok(Sha3CodeGen::mem_lt_size(0x10, 0x10)); + test_ok(Sha3CodeGen::mem_eq_size(0x24, 0x16)); + test_ok(Sha3CodeGen::mem_gt_size(0x32, 0x78)); } #[test] fn sha3_gadget_large() { - test_ok(0x101, 0x202, MemoryKind::Empty); - test_ok(0x202, 0x303, MemoryKind::LessThanSize); - test_ok(0x303, 0x404, MemoryKind::EqualToSize); - test_ok(0x404, 0x505, MemoryKind::MoreThanSize); + test_ok(Sha3CodeGen::mem_empty(0x101, 0x202)); + test_ok(Sha3CodeGen::mem_lt_size(0x202, 0x303)); + test_ok(Sha3CodeGen::mem_eq_size(0x303, 0x404)); + test_ok(Sha3CodeGen::mem_gt_size(0x404, 0x505)); } } diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index f74a6681c6..920cd909b0 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -1,12 +1,11 @@ use std::collections::HashMap; -#[cfg(any(feature = "test", test))] -use crate::evm_circuit::{detect_fixed_table_tags, EvmCircuit}; -#[cfg(feature = "test")] -use crate::util::SubCircuit; - -use crate::{evm_circuit::util::rlc, table::BlockContextFieldTag}; - +use crate::{ + evm_circuit::{detect_fixed_table_tags, util::rlc, EvmCircuit}, + exp_circuit::param::OFFSET_INCREMENT, + table::BlockContextFieldTag, + util::{log2_ceil, SubCircuit}, +}; use bus_mapping::{ circuit_input_builder::{self, CircuitsParams, CopyEvent, ExpEvent}, Error, @@ -59,15 +58,7 @@ impl Block { pub(crate) fn get_rws(&self, step: &ExecStep, index: usize) -> Rw { self.rws[step.rw_index(index)] } -} - -#[cfg(feature = "test")] -use crate::exp_circuit::param::OFFSET_INCREMENT; -#[cfg(feature = "test")] -use crate::util::log2_ceil; -#[cfg(feature = "test")] -impl Block { /// Obtains the expected Circuit degree needed in order to be able to test /// the EvmCircuit with this block without needing to configure the /// `ConstraintSystem`. From 255a9bcec33ef31a9b908401b37fcfe60e09e145 Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 16 May 2023 22:30:49 +0800 Subject: [PATCH 044/102] Add `rustdocflags` config for macos in `Makefile` (#1412) ### Description Add `rustdocflags` override in `Makefile` when it's macos to make doc test work. Note that `config.toml` doesn't support to specify `rustdocflags` under `[target.'cfg(target_os = "macos")']` (see https://github.com/rust-lang/cargo/pull/11323) so we have to use command line override to add it manually. ### Issue Link Resolves https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1410 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### How Has This Been Tested? On macos, run `make test_doc`. Co-authored-by: Chih Cheng Liang --- Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 58656a3448..6dcf6e8420 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,10 @@ +CARGO = cargo + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Darwin) + CARGO += --config 'build.rustdocflags = ["-C", "link-args=-framework CoreFoundation -framework Security"]' +endif + help: ## Display this help screen @grep -h \ -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ @@ -20,8 +27,9 @@ test: ## Run tests for all the workspace members # Run heavy tests serially to avoid OOM @cargo test --release --all --all-features --exclude integration-tests --exclude circuit-benchmarks serial_ -- --ignored --test-threads 1 + test_doc: ## Test the docs - @cargo test --release --all --all-features --doc + @$(CARGO) test --release --all --all-features --doc test_benches: ## Compiles the benchmarks @cargo test --verbose --release --all-features -p circuit-benchmarks --no-run From d21952d2c8b91541f53206caeaf75d847b8df70d Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Tue, 16 May 2023 22:39:01 +0800 Subject: [PATCH 045/102] Retype Gas limit and nonce to u64 (#1409) ### Description - Gas limit from Word to u64 - Nonce from Word to u64 ### Issue Link Fix #1377 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - change geth_type Account's nonce and gas_limit to eth_core::U64. We can not use simple u64 because we need to serialize nonce and gas_limit to hex value with 0x prefix for Geth RPC to use. - simple u64 is used in rest of the places. ### Rationale --- bus-mapping/src/circuit_input_builder.rs | 2 +- .../circuit_input_builder/input_state_ref.rs | 4 +- .../src/circuit_input_builder/tracer_tests.rs | 90 +++++-------------- bus-mapping/src/evm/opcodes/begin_end_tx.rs | 4 +- bus-mapping/src/evm/opcodes/extcodehash.rs | 4 +- bus-mapping/src/mock.rs | 12 +-- bus-mapping/src/state_db.rs | 31 ++++--- eth-types/src/geth_types.rs | 34 +++---- eth-types/src/lib.rs | 8 +- mock/src/account.rs | 8 +- mock/src/test_ctx.rs | 8 +- mock/src/transaction.rs | 16 ++-- testool/src/statetest/executor.rs | 6 +- testool/src/statetest/json.rs | 13 ++- testool/src/statetest/spec.rs | 16 ++-- testool/src/statetest/yaml.rs | 20 ++--- .../src/evm_circuit/execution/begin_tx.rs | 6 +- .../src/evm_circuit/execution/callop.rs | 15 +--- .../execution/error_invalid_jump.rs | 16 +--- .../evm_circuit/execution/error_oog_call.rs | 16 +--- .../execution/error_oog_constant.rs | 16 +--- .../evm_circuit/execution/error_oog_log.rs | 16 +--- .../src/evm_circuit/execution/error_stack.rs | 15 +--- .../execution/error_write_protection.rs | 17 ++-- .../src/evm_circuit/execution/extcodecopy.rs | 5 +- .../src/evm_circuit/execution/extcodehash.rs | 13 ++- .../evm_circuit/execution/return_revert.rs | 22 ++--- zkevm-circuits/src/pi_circuit.rs | 19 ++-- 28 files changed, 171 insertions(+), 281 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 2f351c84cf..057458d073 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -431,7 +431,7 @@ pub fn build_state_code_db( sdb.set_account( &proof.address, state_db::Account { - nonce: proof.nonce, + nonce: proof.nonce.as_u64(), balance: proof.balance, storage, code_hash: proof.code_hash, diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index 21124ad6d7..ffbbc00707 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -276,7 +276,7 @@ impl<'a> CircuitInputStateRef<'a> { // accounts, but the corresponding account in the state DB is empty // (which means code_hash=EMPTY_HASH). let account_value_prev = match op.field { - AccountField::Nonce => account.nonce, + AccountField::Nonce => account.nonce.to_word(), AccountField::Balance => account.balance, AccountField::CodeHash => { if account.is_empty() { @@ -318,7 +318,7 @@ impl<'a> CircuitInputStateRef<'a> { // Perform the write to the account in the StateDB if matches!(rw, RW::WRITE) { match op.field { - AccountField::Nonce => account.nonce = op.value, + AccountField::Nonce => account.nonce = op.value.as_u64(), AccountField::Balance => account.balance = op.value, AccountField::CodeHash => account.code_hash = H256::from(op.value.to_be_bytes()), } diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index ebd4fac6cd..e311af4495 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -250,10 +250,7 @@ fn tracer_err_insufficient_balance() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -406,10 +403,7 @@ fn tracer_err_address_collision() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -529,10 +523,7 @@ fn tracer_create_collision_free() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -573,7 +564,7 @@ fn tracer_create_collision_free() { builder.builder.sdb.set_account( &ADDR_B, Account { - nonce: Word::zero(), + nonce: 0, balance: Word::from(555u64), /* same value as in * `mock::new_tracer_account` */ storage: HashMap::new(), @@ -583,7 +574,7 @@ fn tracer_create_collision_free() { builder.builder.sdb.set_account( &create_address, Account { - nonce: Word::zero(), + nonce: 0, balance: Word::zero(), storage: HashMap::new(), code_hash: Hash::zero(), @@ -662,10 +653,7 @@ fn tracer_err_code_store_out_of_gas() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -715,7 +703,7 @@ fn tracer_err_code_store_out_of_gas_tx_deploy() { txs[0] .from(accs[1].address) .gas(55000u64.into()) - .nonce(Word::zero()) + .nonce(0) .input(code_creator.into()); }, |block, _tx| block.number(0x0264), @@ -814,10 +802,7 @@ fn tracer_err_invalid_code() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -914,10 +899,7 @@ fn tracer_err_max_code_size_exceeded() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -967,7 +949,7 @@ fn tracer_err_max_code_size_exceeded_tx_deploy() { txs[0] .from(accs[1].address) .gas(60000u64.into()) - .nonce(Word::zero()) + .nonce(0) .input(code_creator.into()); }, |block, _tx| block.number(0x0264), @@ -1058,10 +1040,7 @@ fn tracer_create_stop() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1179,10 +1158,7 @@ fn tracer_err_invalid_jump() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1282,10 +1258,7 @@ fn tracer_err_execution_reverted() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1344,10 +1317,7 @@ fn tracer_stop() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1415,10 +1385,7 @@ fn tracer_err_return_data_out_of_bounds() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1571,10 +1538,7 @@ fn tracer_err_write_protection(is_call: bool) { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1776,10 +1740,7 @@ fn create2_address() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1877,10 +1838,7 @@ fn create_address() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1913,7 +1871,7 @@ fn create_address() { builder.builder.sdb.set_account( &ADDR_B, Account { - nonce: Word::from(1), + nonce: 1, ..Account::zero() }, ); @@ -1964,10 +1922,7 @@ fn test_gen_access_trace() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -2189,10 +2144,7 @@ fn test_gen_access_trace_create_push_call_stack() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), diff --git a/bus-mapping/src/evm/opcodes/begin_end_tx.rs b/bus-mapping/src/evm/opcodes/begin_end_tx.rs index 55cc87dff9..d7b6110aad 100644 --- a/bus-mapping/src/evm/opcodes/begin_end_tx.rs +++ b/bus-mapping/src/evm/opcodes/begin_end_tx.rs @@ -55,8 +55,8 @@ fn gen_begin_tx_steps(state: &mut CircuitInputStateRef) -> Result for Account { + fn from(account: geth_types::Account) -> Self { + Self { + nonce: account.nonce.as_u64(), + balance: account.balance, + storage: account.storage.clone(), + code_hash: CodeDB::hash(&account.code.to_vec()), + } + } +} + impl Account { /// Return an empty account, with all values set at zero. pub fn zero() -> Self { Self { - nonce: Word::zero(), + nonce: 0, balance: Word::zero(), storage: HashMap::new(), code_hash: *EMPTY_CODE_HASH, @@ -79,7 +90,7 @@ impl Account { /// Return if account is empty or not. pub fn is_empty(&self) -> bool { - self.nonce.is_zero() && self.balance.is_zero() && self.code_hash.eq(&EMPTY_CODE_HASH) + self.nonce == 0 && self.balance.is_zero() && self.code_hash.eq(&EMPTY_CODE_HASH) } } @@ -187,14 +198,14 @@ impl StateDB { /// Get nonce of account with `addr`. pub fn get_nonce(&self, addr: &Address) -> u64 { let (_, account) = self.get_account(addr); - account.nonce.as_u64() + account.nonce } /// Increase nonce of account with `addr` and return the previous value. pub fn increase_nonce(&mut self, addr: &Address) -> u64 { let (_, account) = self.get_account_mut(addr); - let nonce = account.nonce.as_u64(); - account.nonce = account.nonce + 1; + let nonce = account.nonce; + account.nonce += 1; nonce } @@ -291,12 +302,12 @@ mod statedb_tests { let (found, acc) = statedb.get_account_mut(&addr_a); assert!(!found); assert_eq!(acc, &Account::zero()); - acc.nonce = Word::from(100); + acc.nonce = 100; // Get existing account and check nonce let (found, acc) = statedb.get_account(&addr_a); assert!(found); - assert_eq!(acc.nonce, Word::from(100)); + assert_eq!(acc.nonce, 100); // Get non-existing storage key for existing account and set value let (found, value) = statedb.get_storage_mut(&addr_a, &Word::from(2)); @@ -318,7 +329,7 @@ mod statedb_tests { // Get existing account and check nonce let (found, acc) = statedb.get_account(&addr_b); assert!(found); - assert_eq!(acc.nonce, Word::zero()); + assert_eq!(acc.nonce, 0); // Get existing storage key and check value let (found, value) = statedb.get_storage(&addr_b, &Word::from(3)); diff --git a/eth-types/src/geth_types.rs b/eth-types/src/geth_types.rs index ecd265e469..5756d29a8c 100644 --- a/eth-types/src/geth_types.rs +++ b/eth-types/src/geth_types.rs @@ -3,7 +3,7 @@ use crate::{ sign_types::{biguint_to_32bytes_le, ct_option_ok_or, recover_pk, SignData, SECP256K1_Q}, AccessList, Address, Block, Bytes, Error, GethExecTrace, Hash, ToBigEndian, ToLittleEndian, - Word, U64, + ToWord, Word, U64, }; use ethers_core::{ types::{transaction::response, NameOrAddress, TransactionRequest}, @@ -24,8 +24,9 @@ use std::collections::HashMap; pub struct Account { /// Address pub address: Address, - /// nonce - pub nonce: Word, + /// Nonce. + /// U64 type is required to serialize into proper hex with 0x prefix + pub nonce: U64, /// Balance pub balance: Word, /// EVM Code @@ -64,7 +65,8 @@ pub struct BlockConstants { pub coinbase: Address, /// time pub timestamp: Word, - /// number + /// Block number + /// U64 type is required to serialize into proper hex with 0x prefix pub number: U64, /// difficulty pub difficulty: Word, @@ -119,9 +121,11 @@ pub struct Transaction { /// Avoid direct read from this field. We set this field public to construct the struct pub to: Option
, /// Transaction nonce - pub nonce: Word, + /// U64 type is required to serialize into proper hex with 0x prefix + pub nonce: U64, /// Gas Limit / Supplied gas - pub gas_limit: Word, + /// U64 type is required to serialize into proper hex with 0x prefix + pub gas_limit: U64, /// Transfered value pub value: Word, /// Gas Price @@ -150,8 +154,8 @@ impl From<&Transaction> for crate::Transaction { crate::Transaction { from: tx.from, to: tx.to, - nonce: tx.nonce, - gas: tx.gas_limit, + nonce: tx.nonce.to_word(), + gas: tx.gas_limit.to_word(), value: tx.value, gas_price: Some(tx.gas_price), max_priority_fee_per_gas: Some(tx.gas_fee_cap), @@ -171,8 +175,8 @@ impl From<&crate::Transaction> for Transaction { Transaction { from: tx.from, to: tx.to, - nonce: tx.nonce, - gas_limit: tx.gas, + nonce: tx.nonce.as_u64().into(), + gas_limit: tx.gas.as_u64().into(), value: tx.value, gas_price: tx.gas_price.unwrap_or_default(), gas_fee_cap: tx.max_priority_fee_per_gas.unwrap_or_default(), @@ -191,11 +195,11 @@ impl From<&Transaction> for TransactionRequest { TransactionRequest { from: Some(tx.from), to: tx.to.map(NameOrAddress::Address), - gas: Some(tx.gas_limit), + gas: Some(tx.gas_limit.to_word()), gas_price: Some(tx.gas_price), value: Some(tx.value), data: Some(tx.call_data.clone()), - nonce: Some(tx.nonce), + nonce: Some(tx.nonce.to_word()), ..Default::default() } } @@ -256,7 +260,7 @@ impl Transaction { /// Get the "to" address. If `to` is None then compute contract adddress pub fn to_or_contract_addr(&self) -> Address { self.to - .unwrap_or_else(|| get_contract_address(self.from, self.nonce)) + .unwrap_or_else(|| get_contract_address(self.from, self.nonce.to_word())) } /// Determine if this transaction is a contract create transaction pub fn is_create(&self) -> bool { @@ -277,8 +281,8 @@ impl Transaction { input: self.call_data.clone(), gas_price: Some(self.gas_price), access_list: self.access_list.clone(), - nonce: self.nonce, - gas: self.gas_limit, + nonce: self.nonce.to_word(), + gas: self.gas_limit.to_word(), transaction_index: Some(transaction_index), r: self.r, s: self.s, diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index 21e2486f61..e3417d6e50 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -241,6 +241,12 @@ impl ToWord for i32 { } } +impl ToWord for U64 { + fn to_word(&self) -> Word { + self.as_u64().into() + } +} + impl ToWord for Word { fn to_word(&self) -> Word { *self @@ -296,7 +302,7 @@ pub struct EIP1186ProofResponse { /// The hash of the code of the account pub code_hash: H256, /// The nonce of the account - pub nonce: U256, + pub nonce: U64, /// SHA3 of the StorageRoot pub storage_hash: H256, /// Array of rlp-serialized MerkleTree-Nodes diff --git a/mock/src/account.rs b/mock/src/account.rs index 0cdda75549..87abb710e8 100644 --- a/mock/src/account.rs +++ b/mock/src/account.rs @@ -11,7 +11,7 @@ pub struct MockAccount { /// Address pub address: Address, /// nonce - pub nonce: Word, + pub nonce: u64, /// Balance pub balance: Word, /// EVM Code @@ -24,7 +24,7 @@ impl From for Account { fn from(mock: MockAccount) -> Self { Account { address: mock.address, - nonce: mock.nonce, + nonce: mock.nonce.into(), balance: mock.balance, code: mock.code, storage: mock.storage, @@ -40,7 +40,7 @@ impl MockAccount { } /// Set nonce field for the MockAccount. - pub fn nonce(&mut self, nonce: Word) -> &mut Self { + pub fn nonce(&mut self, nonce: u64) -> &mut Self { self.nonce = nonce; self } @@ -69,7 +69,7 @@ impl MockAccount { /// Set all fields for the MockAccount based on their values in `account`. pub fn account(&mut self, account: &Account) -> &mut Self { self.address(account.address); - self.nonce(account.nonce); + self.nonce(account.nonce.as_u64()); self.balance(account.balance); self.code(account.code.clone()); self.storage(account.storage.iter().map(|(k, v)| (*k, *v))); diff --git a/mock/src/test_ctx.rs b/mock/src/test_ctx.rs index 5da3907901..befff9f3e0 100644 --- a/mock/src/test_ctx.rs +++ b/mock/src/test_ctx.rs @@ -66,7 +66,7 @@ pub use external_tracer::LoggerConfig; /// txs[1] /// .to(accs[1].address) /// .from(accs[2].address) -/// .nonce(Word::one()); +/// .nonce(1); /// }, /// |block, _tx| block.number(0xcafeu64), /// ) @@ -141,10 +141,8 @@ impl TestContext { .enumerate() .skip(1) .for_each(|(idx, tx)| { - tx.transaction_idx(u64::try_from(idx).expect("Unexpected idx conversion error")); - tx.nonce(Word::from( - u64::try_from(idx).expect("Unexpected idx conversion error"), - )); + let idx = u64::try_from(idx).expect("Unexpected idx conversion error"); + tx.transaction_idx(idx).nonce(idx); }); let tx_refs = transactions.iter_mut().collect(); diff --git a/mock/src/transaction.rs b/mock/src/transaction.rs index 9bb9b00291..1b6c6ccd1f 100644 --- a/mock/src/transaction.rs +++ b/mock/src/transaction.rs @@ -23,7 +23,7 @@ lazy_static! { vec![MockTransaction::default() .from(AddrOrWallet::random(&mut rng)) .to(MOCK_ACCOUNTS[0]) - .nonce(word!("0x103")) + .nonce(0x103u64) .value(word!("0x3e8")) .gas_price(word!("0x4d2")) .input(Bytes::from(b"hello")) @@ -31,7 +31,7 @@ lazy_static! { MockTransaction::default() .from(AddrOrWallet::random(&mut rng)) .to(MOCK_ACCOUNTS[1]) - .nonce(word!("0x104")) + .nonce(0x104u64) .value(word!("0x3e8")) .gas_price(word!("0x4d2")) .input(Bytes::from(b"hello")) @@ -39,7 +39,7 @@ lazy_static! { MockTransaction::default() .from(AddrOrWallet::random(&mut rng)) .to(MOCK_ACCOUNTS[2]) - .nonce(word!("0x105")) + .nonce(0x105u64) .value(word!("0x3e8")) .gas_price(word!("0x4d2")) .input(Bytes::from(b"hello")) @@ -47,7 +47,7 @@ lazy_static! { MockTransaction::default() .from(AddrOrWallet::random(&mut rng)) .to(MOCK_ACCOUNTS[0]) - .nonce(word!("0x106")) + .nonce(0x106u64) .value(word!("0x3e8")) .gas_price(word!("0x4d2")) .input(Bytes::from(b"hello")) @@ -119,7 +119,7 @@ impl AddrOrWallet { /// any of it's details. pub struct MockTransaction { pub hash: Option, - pub nonce: Word, + pub nonce: u64, pub block_hash: Hash, pub block_number: U64, pub transaction_index: U64, @@ -143,7 +143,7 @@ impl Default for MockTransaction { fn default() -> Self { MockTransaction { hash: None, - nonce: Word::zero(), + nonce: 0, block_hash: Hash::zero(), block_number: U64::zero(), transaction_index: U64::zero(), @@ -169,7 +169,7 @@ impl From for Transaction { fn from(mock: MockTransaction) -> Self { Transaction { hash: mock.hash.unwrap_or_default(), - nonce: mock.nonce, + nonce: mock.nonce.into(), block_hash: Some(mock.block_hash), block_number: Some(mock.block_number), transaction_index: Some(mock.transaction_index), @@ -207,7 +207,7 @@ impl MockTransaction { } /// Set nonce field for the MockTransaction. - pub fn nonce(&mut self, nonce: Word) -> &mut Self { + pub fn nonce(&mut self, nonce: u64) -> &mut Self { self.nonce = nonce; self } diff --git a/testool/src/statetest/executor.rs b/testool/src/statetest/executor.rs index 16cd0927f1..c2c365d8f1 100644 --- a/testool/src/statetest/executor.rs +++ b/testool/src/statetest/executor.rs @@ -23,7 +23,7 @@ pub enum StateTestError { #[error("BalanceMismatch(expected:{expected:?}, found:{found:?})")] BalanceMismatch { expected: U256, found: U256 }, #[error("NonceMismatch(expected:{expected:?}, found:{found:?})")] - NonceMismatch { expected: U256, found: U256 }, + NonceMismatch { expected: u64, found: u64 }, #[error("CodeMismatch(expected: {expected:?}, found:{found:?})")] CodeMismatch { expected: Bytes, found: Bytes }, #[error("StorgeMismatch(slot:{slot:?} expected:{expected:?}, found: {found:?})")] @@ -139,9 +139,9 @@ fn into_traceconfig(st: StateTest) -> (String, TraceConfig, StateTestResult) { transactions: vec![geth_types::Transaction { from: st.from, to: st.to, - nonce: st.nonce, + nonce: U64::from(st.nonce), value: st.value, - gas_limit: st.gas_limit.into(), + gas_limit: U64::from(st.gas_limit), gas_price: st.gas_price, gas_fee_cap: U256::zero(), gas_tip_cap: U256::zero(), diff --git a/testool/src/statetest/json.rs b/testool/src/statetest/json.rs index 14c042720f..7bd35e26b7 100644 --- a/testool/src/statetest/json.rs +++ b/testool/src/statetest/json.rs @@ -108,7 +108,7 @@ impl<'a> JsonStateTestBuilder<'a> { let to = parse::parse_to_address(&test.transaction.to)?; let secret_key = parse::parse_bytes(&test.transaction.secret_key)?; let from = secret_key_to_address(&SigningKey::from_bytes(&secret_key.to_vec())?); - let nonce = parse::parse_u256(&test.transaction.nonce)?; + let nonce = parse::parse_u64(&test.transaction.nonce)?; let gas_price = parse::parse_u256(&test.transaction.gas_price)?; let data_s: Vec<_> = test @@ -215,7 +215,7 @@ impl<'a> JsonStateTestBuilder<'a> { let account = Account { address, balance: parse::parse_u256(&acc.balance)?, - nonce: parse::parse_u256(&acc.nonce)?, + nonce: parse::parse_u64(&acc.nonce)?.into(), code: parse::parse_code(self.compiler, &acc.code)?, storage, }; @@ -253,7 +253,7 @@ impl<'a> JsonStateTestBuilder<'a> { nonce: acc .nonce .as_ref() - .map(|v| parse::parse_u256(v)) + .map(|v| parse::parse_u64(v)) .transpose()?, storage, }; @@ -388,24 +388,23 @@ mod test { )?), gas_limit: 400000, gas_price: U256::from(10u64), - nonce: U256::from(0u64), + nonce: 0, value: U256::from(100000u64), data: Bytes::from(hex::decode("6001")?), pre: HashMap::from([( acc095e, Account { address: acc095e, - nonce: U256::from(0u64), balance: U256::from(1000000000000000000u64), code: Bytes::from(hex::decode("600160010160005500")?), - storage: HashMap::new(), + ..Default::default() }, )]), result: HashMap::from([( acc095e, AccountMatch { address: acc095e, - nonce: Some(U256::from(1u64)), + nonce: Some(1u64), balance: None, code: Some(Bytes::from(hex::decode("600160010160005500")?)), storage: HashMap::from([(U256::zero(), U256::from(2u64))]), diff --git a/testool/src/statetest/spec.rs b/testool/src/statetest/spec.rs index 12b06baa14..234867ccda 100644 --- a/testool/src/statetest/spec.rs +++ b/testool/src/statetest/spec.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, bail, Context}; -use eth_types::{geth_types::Account, Address, Bytes, Word, H256, U256}; +use eth_types::{geth_types::Account, Address, Bytes, Word, H256, U256, U64}; use ethers_core::{k256::ecdsa::SigningKey, utils::secret_key_to_address}; use std::{collections::HashMap, str::FromStr}; @@ -18,7 +18,7 @@ pub struct AccountMatch { pub address: Address, pub balance: Option, pub code: Option, - pub nonce: Option, + pub nonce: Option, pub storage: HashMap, } @@ -29,7 +29,7 @@ impl TryInto for AccountMatch { address: self.address, balance: self.balance.context("balance")?, code: self.code.context("code")?, - nonce: self.nonce.context("nonce")?, + nonce: self.nonce.context("nonce")?.into(), storage: self.storage, }) } @@ -47,7 +47,7 @@ pub struct StateTest { pub to: Option
, pub gas_limit: u64, pub gas_price: U256, - pub nonce: U256, + pub nonce: u64, pub value: U256, pub data: Bytes, pub pre: HashMap, @@ -205,10 +205,8 @@ impl StateTest { from, Account { address: from, - nonce: U256::zero(), balance: U256::from(10).pow(18.into()), - code: Bytes::default(), - storage: HashMap::new(), + ..Default::default() }, ); @@ -242,7 +240,7 @@ impl StateTest { address, Account { address, - nonce: U256::one(), + nonce: U64::one(), code: Bytes::from(code.code()), balance, storage, @@ -275,7 +273,7 @@ impl StateTest { to, gas_limit, gas_price: U256::one(), - nonce: U256::zero(), + nonce: 0, value, data: data.into(), pre, diff --git a/testool/src/statetest/yaml.rs b/testool/src/statetest/yaml.rs index 20b8c4cd7c..28bee90c17 100644 --- a/testool/src/statetest/yaml.rs +++ b/testool/src/statetest/yaml.rs @@ -104,7 +104,7 @@ impl<'a> YamlStateTestBuilder<'a> { Self::parse_u256(&yaml_transaction["gasPrice"]).unwrap_or_else(|_| U256::one()); // TODO handle maxPriorityFeePerGas & maxFeePerGas - let nonce = Self::parse_u256(&yaml_transaction["nonce"])?; + let nonce = Self::parse_u64(&yaml_transaction["nonce"])?; let to = Self::parse_to_address(&yaml_transaction["to"])?; let secret_key = Self::parse_bytes(&yaml_transaction["secretKey"])?; let from = secret_key_to_address(&SigningKey::from_bytes(&secret_key.to_vec())?); @@ -244,7 +244,7 @@ impl<'a> YamlStateTestBuilder<'a> { nonce: if acc_nonce.is_badvalue() { None } else { - Some(Self::parse_u256(acc_nonce)?) + Some(Self::parse_u64(acc_nonce)?) }, storage, }; @@ -615,7 +615,7 @@ arith: to: Some(ccccc), gas_limit: 80000000, gas_price: U256::from(10u64), - nonce: U256::zero(), + nonce: 0, value: U256::one(), data: Bytes::from(&[0]), pre: HashMap::from([ @@ -625,9 +625,8 @@ arith: address: ccccc, balance: U256::from(1000000000000u64), code: Bytes::from(&[0x60, 0x01, 0x00]), - nonce: U256::zero(), - storage: HashMap::from([(U256::zero(), U256::one())]), + ..Default::default() }, ), ( @@ -635,10 +634,7 @@ arith: Account { address: a94f5, balance: U256::from(1000000000000u64), - code: Bytes::default(), - nonce: U256::zero(), - - storage: HashMap::new(), + ..Default::default() }, ), ]), @@ -647,7 +643,7 @@ arith: AccountMatch { address: ccccc, balance: Some(U256::from(1000000000001u64)), - nonce: Some(U256::from(0)), + nonce: Some(0), code: Some(Bytes::from(&[0x60, 0x01, 0x00])), storage: HashMap::from([(U256::zero(), U256::one())]), }, @@ -762,8 +758,8 @@ arith: CircuitsConfig::default() ), Err(StateTestError::NonceMismatch { - expected: U256::from(2), - found: U256::from(0) + expected: 2, + found: 0 }) ); diff --git a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs index 230fe1d549..39c404ce50 100644 --- a/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/begin_tx.rs @@ -664,7 +664,7 @@ mod test { // This test checks that the rw table assignment and evm circuit are consistent // in not applying an RLC to account and tx nonces. // https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/592 - let multibyte_nonce = Word::from(700); + let multibyte_nonce = 700; let to = MOCK_ACCOUNTS[0]; let from = MOCK_ACCOUNTS[1]; @@ -776,12 +776,12 @@ mod test { accs[0] .address(MOCK_ACCOUNTS[0]) .balance(eth(20)) - .nonce(nonce.into()); + .nonce(nonce); }, |mut txs, _accs| { txs[0] .from(MOCK_ACCOUNTS[0]) - .nonce(nonce.into()) + .nonce(nonce) .gas_price(gwei(2)) .gas(Word::from(0x10000)) .value(eth(2)) diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index de36e6462a..7aae484769 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -618,6 +618,7 @@ mod test { use bus_mapping::circuit_input_builder::CircuitsParams; use eth_types::{ address, bytecode, evm_types::OpcodeId, geth_types::Account, word, Address, ToWord, Word, + U64, }; use itertools::Itertools; @@ -747,7 +748,7 @@ mod test { Account { address: Address::repeat_byte(0xff), code: code.into(), - nonce: if is_empty { 0 } else { 1 }.into(), + nonce: U64::from(!is_empty as u64), balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), ..Default::default() } @@ -874,16 +875,8 @@ mod test { accs[0] .address(address!("0x000000000000000000000000000000000000cafe")) .balance(Word::from(10u64.pow(19))); - accs[1] - .address(caller.address) - .code(caller.code) - .nonce(caller.nonce) - .balance(caller.balance); - accs[2] - .address(callee.address) - .code(callee.code) - .nonce(callee.nonce) - .balance(callee.balance); + accs[1].account(&caller); + accs[2].account(&callee); }, |mut txs, accs| { txs[0] diff --git a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs index 44d0642f29..888c340aba 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs @@ -185,7 +185,7 @@ mod test { use crate::test_util::CircuitTestBuilder; use eth_types::{ address, bytecode, bytecode::Bytecode, evm_types::OpcodeId, geth_types::Account, Address, - ToWord, Word, + ToWord, Word, U64, }; use mock::TestContext; @@ -258,7 +258,7 @@ mod test { Account { address: Address::repeat_byte(0xff), code: code.into(), - nonce: if is_empty { 0 } else { 1 }.into(), + nonce: U64::from(!is_empty as u64), balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), ..Default::default() } @@ -382,16 +382,8 @@ mod test { accs[0] .address(address!("0x000000000000000000000000000000000000cafe")) .balance(Word::from(10u64.pow(19))); - accs[1] - .address(caller.address) - .code(caller.code) - .nonce(caller.nonce) - .balance(caller.balance); - accs[2] - .address(callee.address) - .code(callee.code) - .nonce(callee.nonce) - .balance(callee.balance); + accs[1].account(&caller); + accs[2].account(&callee); }, |mut txs, accs| { txs[0] diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs index 07884165b9..c97932ac33 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs @@ -227,7 +227,7 @@ mod test { use crate::test_util::CircuitTestBuilder; use eth_types::{ address, bytecode, bytecode::Bytecode, evm_types::OpcodeId, geth_types::Account, Address, - ToWord, Word, + ToWord, Word, U64, }; use mock::TestContext; use std::default::Default; @@ -288,7 +288,7 @@ mod test { Account { address: Address::repeat_byte(0xff), code: code.into(), - nonce: if is_empty { 0 } else { 1 }.into(), + nonce: U64::from(!is_empty as u64), balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), ..Default::default() } @@ -302,16 +302,8 @@ mod test { accs[0] .address(address!("0x000000000000000000000000000000000000cafe")) .balance(Word::from(10u64.pow(19))); - accs[1] - .address(caller.address) - .code(caller.code.clone()) - .nonce(caller.nonce) - .balance(caller.balance); - accs[2] - .address(callee.address) - .code(callee.code.clone()) - .nonce(callee.nonce) - .balance(callee.balance); + accs[1].account(caller); + accs[2].account(callee); }, |mut txs, accs| { txs[0] diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs index 0dff4423ec..350a546d15 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs @@ -94,7 +94,7 @@ mod test { use bus_mapping::evm::OpcodeId; use eth_types::{ self, address, bytecode, bytecode::Bytecode, evm_types::GasCost, geth_types::Account, - Address, ToWord, Word, + Address, ToWord, Word, U64, }; use mock::{ @@ -226,16 +226,8 @@ mod test { accs[0] .address(address!("0x000000000000000000000000000000000000cafe")) .balance(Word::from(10u64.pow(19))); - accs[1] - .address(caller.address) - .code(caller.code) - .nonce(caller.nonce) - .balance(caller.balance); - accs[2] - .address(callee.address) - .code(callee.code) - .nonce(callee.nonce) - .balance(callee.balance); + accs[1].account(&caller); + accs[2].account(&callee); }, |mut txs, accs| { txs[0] @@ -256,7 +248,7 @@ mod test { Account { address: Address::repeat_byte(0xff), code: code.into(), - nonce: if is_empty { 0 } else { 1 }.into(), + nonce: U64::from(!is_empty as u64), balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), ..Default::default() } diff --git a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs index daa2dda87c..885a10e7ae 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs @@ -145,7 +145,7 @@ mod test { use bus_mapping::evm::OpcodeId; use eth_types::{ self, address, bytecode, bytecode::Bytecode, evm_types::GasCost, geth_types::Account, - Address, ToWord, Word, + Address, ToWord, Word, U64, }; use mock::{ @@ -267,16 +267,8 @@ mod test { accs[0] .address(address!("0x000000000000000000000000000000000000cafe")) .balance(Word::from(10u64.pow(19))); - accs[1] - .address(caller.address) - .code(caller.code) - .nonce(caller.nonce) - .balance(caller.balance); - accs[2] - .address(callee.address) - .code(callee.code) - .nonce(callee.nonce) - .balance(callee.balance); + accs[1].account(&caller); + accs[2].account(&callee); }, |mut txs, accs| { txs[0] @@ -297,7 +289,7 @@ mod test { Account { address: Address::repeat_byte(0xff), code: code.into(), - nonce: if is_empty { 0 } else { 1 }.into(), + nonce: U64::from(!is_empty as u64), balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), ..Default::default() } diff --git a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs index bb0d1d5967..61d746d83e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_stack.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_stack.rs @@ -75,6 +75,7 @@ mod test { use bus_mapping::{circuit_input_builder::CircuitsParams, evm::OpcodeId}; use eth_types::{ self, address, bytecode, bytecode::Bytecode, geth_types::Account, Address, ToWord, Word, + U64, }; use mock::TestContext; @@ -199,16 +200,8 @@ mod test { accs[0] .address(address!("0x000000000000000000000000000000000000cafe")) .balance(Word::from(10u64.pow(19))); - accs[1] - .address(caller.address) - .code(caller.code) - .nonce(caller.nonce) - .balance(caller.balance); - accs[2] - .address(callee.address) - .code(callee.code) - .nonce(callee.nonce) - .balance(callee.balance); + accs[1].account(&caller); + accs[2].account(&callee); }, |mut txs, accs| { txs[0] @@ -229,7 +222,7 @@ mod test { Account { address: Address::repeat_byte(0xff), code: code.into(), - nonce: if is_empty { 0 } else { 1 }.into(), + nonce: U64::from(!is_empty as u64), balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), ..Default::default() } diff --git a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs index 83b168c05b..0f1fbe7a0c 100644 --- a/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs +++ b/zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs @@ -143,7 +143,7 @@ mod test { use crate::test_util::CircuitTestBuilder; use eth_types::{ address, bytecode, bytecode::Bytecode, evm_types::OpcodeId, geth_types::Account, Address, - ToWord, Word, + ToWord, Word, U64, }; use mock::TestContext; @@ -160,10 +160,11 @@ mod test { fn callee(code: Bytecode) -> Account { let code = code.to_vec(); let is_empty = code.is_empty(); + Account { address: Address::repeat_byte(0xff), code: code.into(), - nonce: if is_empty { 0 } else { 1 }.into(), + nonce: U64::from(!is_empty as u64), balance: if is_empty { 0 } else { 0xdeadbeefu64 }.into(), ..Default::default() } @@ -284,16 +285,8 @@ mod test { accs[0] .address(address!("0x000000000000000000000000000000000000cafe")) .balance(Word::from(10u64.pow(19))); - accs[1] - .address(caller.address) - .code(caller.code) - .nonce(caller.nonce) - .balance(caller.balance); - accs[2] - .address(callee.address) - .code(callee.code) - .nonce(callee.nonce) - .balance(callee.balance); + accs[1].account(&caller); + accs[2].account(&callee); }, |mut txs, accs| { txs[0] diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index 5bc7f6d307..fcecb36866 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -291,10 +291,7 @@ mod test { .balance(Word::from(1u64 << 20)); accs[2].address(external_address); if let Some(external_account) = external_account { - accs[2] - .balance(external_account.balance) - .nonce(external_account.nonce) - .code(external_account.code); + accs[2].account(&external_account); } }, |mut txs, accs| { diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs index a30ba0dad3..1d14cffa34 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodehash.rs @@ -122,7 +122,7 @@ impl ExecutionGadget for ExtcodehashGadget { mod test { use crate::test_util::CircuitTestBuilder; use eth_types::{ - address, bytecode, geth_types::Account, Address, Bytecode, Bytes, ToWord, Word, U256, + address, bytecode, geth_types::Account, Address, Bytecode, Bytes, ToWord, Word, U256, U64, }; use lazy_static::lazy_static; use mock::TestContext; @@ -134,7 +134,7 @@ mod test { fn test_ok(external_account: Option, is_warm: bool) { let external_address = external_account - .as_ref() + .clone() .map(|a| a.address) .unwrap_or(*EXTERNAL_ADDRESS); @@ -166,10 +166,7 @@ mod test { accs[1].address(external_address); if let Some(external_account) = external_account { - accs[1] - .balance(external_account.balance) - .nonce(external_account.nonce) - .code(external_account.code); + accs[1].account(&external_account); } accs[2] .address(address!("0x0000000000000000000000000000000000000010")) @@ -200,7 +197,7 @@ mod test { test_ok( Some(Account { address: *EXTERNAL_ADDRESS, - nonce: U256::from(259), + nonce: U64::from(259), code: Bytes::from([3]), ..Default::default() }), @@ -227,7 +224,7 @@ mod test { // code = []. let nonce_only_account = Account { address: *EXTERNAL_ADDRESS, - nonce: U256::from(200), + nonce: U64::from(200), ..Default::default() }; // This account state is possible if another account sends ETH to a previously diff --git a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs index 4fef4795e9..e584a2d8d5 100644 --- a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs +++ b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs @@ -347,7 +347,7 @@ mod test { address, bytecode, evm_types::OpcodeId, geth_types::{Account, GethData}, - Address, Bytecode, ToWord, Word, U256, + Address, Bytecode, Bytes, ToWord, Word, U256, U64, }; use itertools::Itertools; use mock::{eth, TestContext, MOCK_ACCOUNTS}; @@ -420,13 +420,13 @@ mod test { let callee = Account { address: CALLEE_ADDRESS, code: callee_bytecode(*is_return, *callee_offset, *callee_length).into(), - nonce: Word::one(), + nonce: U64::one(), ..Default::default() }; let caller = Account { address: CALLER_ADDRESS, code: caller_bytecode(*caller_offset, *caller_length).into(), - nonce: Word::one(), + nonce: U64::one(), ..Default::default() }; @@ -496,21 +496,17 @@ mod test { CREATE }; - let caller = Account { - address: CALLER_ADDRESS, - code: root_code.into(), - nonce: Word::one(), - balance: eth(10), - ..Default::default() - }; - let ctx = TestContext::<2, 1>::new( None, |accs| { accs[0] .address(address!("0x000000000000000000000000000000000000cafe")) .balance(eth(10)); - accs[1].account(&caller); + accs[1] + .address(CALLER_ADDRESS) + .code::(root_code.into()) + .nonce(1) + .balance(eth(10)); }, |mut txs, accs| { txs[0] @@ -550,7 +546,7 @@ mod test { let caller = Account { address: CALLER_ADDRESS, code: root_code.into(), - nonce: Word::one(), + nonce: U64::one(), balance: eth(10), ..Default::default() }; diff --git a/zkevm-circuits/src/pi_circuit.rs b/zkevm-circuits/src/pi_circuit.rs index d5b4523ebd..3e45581d89 100644 --- a/zkevm-circuits/src/pi_circuit.rs +++ b/zkevm-circuits/src/pi_circuit.rs @@ -51,8 +51,8 @@ pub struct BlockValues { /// Values of the tx table (as in the spec) #[derive(Default, Debug, Clone)] pub struct TxValues { - nonce: Word, - gas: Word, // gas limit + nonce: u64, + gas: u64, // gas limit gas_price: Word, from_addr: Address, to_addr: Address, @@ -139,9 +139,9 @@ impl PublicData { let mut msg_hash_le = [0u8; 32]; msg_hash_le.copy_from_slice(sign_data.msg_hash.to_bytes().as_slice()); tx_vals.push(TxValues { - nonce: tx.nonce, + nonce: tx.nonce.as_u64(), gas_price: tx.gas_price, - gas: tx.gas_limit, + gas: tx.gas_limit.as_u64(), from_addr: tx.from, to_addr: tx.to_or_zero(), is_create: tx.is_create(), @@ -1317,11 +1317,8 @@ impl SubCircuit for PiCircuit { let tx = if i < txs.len() { &txs[i] } else { &tx_default }; for (tag, value) in &[ - ( - TxFieldTag::Nonce, - rlc(tx.nonce.to_le_bytes(), self.randomness), - ), - (TxFieldTag::Gas, rlc(tx.gas.to_le_bytes(), self.randomness)), + (TxFieldTag::Nonce, F::from(tx.nonce)), + (TxFieldTag::Gas, F::from(tx.gas)), ( TxFieldTag::GasPrice, rlc(tx.gas_price.to_le_bytes(), self.randomness), @@ -1520,8 +1517,8 @@ fn raw_public_inputs_col( let tx = if i < txs.len() { &txs[i] } else { &tx_default }; for val in &[ - rlc(tx.nonce.to_le_bytes(), randomness), - rlc(tx.gas.to_le_bytes(), randomness), + F::from(tx.nonce), + F::from(tx.gas), rlc(tx.gas_price.to_le_bytes(), randomness), tx.from_addr.to_scalar().expect("tx.from too big"), tx.to_addr.to_scalar().expect("tx.to too big"), From 438bac5bd09fa5fc9472d7f58f847d4e083b2fdc Mon Sep 17 00:00:00 2001 From: Paul <108982045+ChengYueJia@users.noreply.github.com> Date: Wed, 17 May 2023 18:03:00 +0800 Subject: [PATCH 046/102] Split table into files (#1402) ### Description Split table into files. * prior This is one the new pr of #1061 --------- Co-authored-by: Chih Cheng Liang --- zkevm-circuits/src/evm_circuit/table.rs | 1 - zkevm-circuits/src/table.rs | 1386 +------------------- zkevm-circuits/src/table/block_table.rs | 100 ++ zkevm-circuits/src/table/bytecode_table.rs | 105 ++ zkevm-circuits/src/table/copy_table.rs | 304 +++++ zkevm-circuits/src/table/exp_table.rs | 215 +++ zkevm-circuits/src/table/keccak_table.rs | 146 +++ zkevm-circuits/src/table/mpt_table.rs | 103 ++ zkevm-circuits/src/table/rw_table.rs | 202 +++ zkevm-circuits/src/table/tx_table.rs | 217 +++ 10 files changed, 1422 insertions(+), 1357 deletions(-) create mode 100644 zkevm-circuits/src/table/block_table.rs create mode 100644 zkevm-circuits/src/table/bytecode_table.rs create mode 100644 zkevm-circuits/src/table/copy_table.rs create mode 100644 zkevm-circuits/src/table/exp_table.rs create mode 100644 zkevm-circuits/src/table/keccak_table.rs create mode 100644 zkevm-circuits/src/table/mpt_table.rs create mode 100644 zkevm-circuits/src/table/rw_table.rs create mode 100644 zkevm-circuits/src/table/tx_table.rs diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index cc71063003..b3d44f6459 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -1,4 +1,3 @@ -pub use crate::table::TxContextFieldTag; use crate::{ evm_circuit::step::{ExecutionState, ResponsibleOp}, impl_expr, diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 4f69656e36..538b894c5b 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -3,17 +3,13 @@ use crate::{ copy_circuit::util::number_or_hash_to_field, evm_circuit::util::rlc, - exp_circuit::param::{OFFSET_INCREMENT, ROWS_PER_STEP}, impl_expr, util::{build_tx_log_address, Challenges}, witness::{ Block, BlockContext, Bytecode, MptUpdateRow, MptUpdates, Rw, RwMap, RwRow, Transaction, }, }; -use bus_mapping::{ - circuit_input_builder::{CopyDataType, CopyEvent, CopyStep, ExpEvent}, - operation::Target, -}; +use bus_mapping::circuit_input_builder::{CopyDataType, CopyEvent, CopyStep}; use core::iter::once; use eth_types::{Field, ToLittleEndian, ToScalar, Word, U256}; use gadgets::{ @@ -30,6 +26,35 @@ use keccak256::plain::Keccak; use std::array; use strum_macros::{EnumCount, EnumIter}; +/// block table +pub(crate) mod block_table; +/// bytecode table +pub(crate) mod bytecode_table; +/// copy Table +pub(crate) mod copy_table; +/// exp(exponentiation) table +pub(crate) mod exp_table; +/// keccak table +pub(crate) mod keccak_table; +/// mpt table +pub(crate) mod mpt_table; +/// rw table +pub(crate) mod rw_table; +/// tx table +pub(crate) mod tx_table; + +pub(crate) use block_table::{BlockContextFieldTag, BlockTable}; +pub(crate) use bytecode_table::{BytecodeFieldTag, BytecodeTable}; +pub(crate) use copy_table::CopyTable; +pub(crate) use exp_table::ExpTable; +pub(crate) use keccak_table::KeccakTable; + +pub(crate) use mpt_table::{MPTProofType, MptTable}; +pub(crate) use rw_table::{RwTable, RwTableTag}; +pub(crate) use tx_table::{ + TxContextFieldTag, TxFieldTag, TxLogFieldTag, TxReceiptFieldTag, TxTable, +}; + /// Trait used to define lookup tables pub trait LookupTable { /// Returns the list of ALL the table columns following the table order. @@ -90,264 +115,6 @@ impl> + Copy, const W: usize> LookupTable for [ } } -/// Tag used to identify each field in the transaction in a row of the -/// transaction table. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum TxFieldTag { - /// Unused tag - Null = 0, - /// Nonce - Nonce, - /// Gas - Gas, - /// GasPrice - GasPrice, - /// CallerAddress - CallerAddress, - /// CalleeAddress - CalleeAddress, - /// IsCreate - IsCreate, - /// Value - Value, - /// CallDataLength - CallDataLength, - /// Gas cost for transaction call data (4 for byte == 0, 16 otherwise) - CallDataGasCost, - /// TxSignHash: Hash of the transaction without the signature, used for - /// signing. - TxSignHash, - /// CallData - CallData, -} -impl_expr!(TxFieldTag); - -/// Alias for TxFieldTag used by EVM Circuit -pub type TxContextFieldTag = TxFieldTag; - -/// Table that contains the fields of all Transactions in a block -#[derive(Clone, Debug)] -pub struct TxTable { - /// Tx ID - pub tx_id: Column, - /// Tag (TxContextFieldTag) - pub tag: Column, - /// Index for Tag = CallData - pub index: Column, - /// Value - pub value: Column, -} - -impl TxTable { - /// Construct a new TxTable - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - tx_id: meta.advice_column(), - tag: meta.fixed_column(), - index: meta.advice_column(), - value: meta.advice_column_in(SecondPhase), - } - } - - /// Assign the `TxTable` from a list of block `Transaction`s, followig the - /// same layout that the Tx Circuit uses. - pub fn load( - &self, - layouter: &mut impl Layouter, - txs: &[Transaction], - max_txs: usize, - max_calldata: usize, - challenges: &Challenges>, - ) -> Result<(), Error> { - assert!( - txs.len() <= max_txs, - "txs.len() <= max_txs: txs.len()={}, max_txs={}", - txs.len(), - max_txs - ); - let sum_txs_calldata = txs.iter().map(|tx| tx.call_data.len()).sum(); - assert!( - sum_txs_calldata <= max_calldata, - "sum_txs_calldata <= max_calldata: sum_txs_calldata={}, max_calldata={}", - sum_txs_calldata, - max_calldata, - ); - - fn assign_row( - region: &mut Region<'_, F>, - offset: usize, - advice_columns: &[Column], - tag: &Column, - row: &[Value; 4], - msg: &str, - ) -> Result<(), Error> { - for (index, column) in advice_columns.iter().enumerate() { - region.assign_advice( - || format!("tx table {} row {}", msg, offset), - *column, - offset, - || row[if index > 0 { index + 1 } else { index }], - )?; - } - region.assign_fixed( - || format!("tx table {} row {}", msg, offset), - *tag, - offset, - || row[1], - )?; - Ok(()) - } - - layouter.assign_region( - || "tx table", - |mut region| { - let mut offset = 0; - let advice_columns = [self.tx_id, self.index, self.value]; - assign_row( - &mut region, - offset, - &advice_columns, - &self.tag, - &[(); 4].map(|_| Value::known(F::ZERO)), - "all-zero", - )?; - offset += 1; - - // Tx Table contains an initial region that has a size parametrized by max_txs - // with all the tx data except for calldata, and then a second - // region that has a size parametrized by max_calldata with all - // the tx calldata. This is required to achieve a constant fixed column tag - // regardless of the number of input txs or the calldata size of each tx. - let mut calldata_assignments: Vec<[Value; 4]> = Vec::new(); - // Assign Tx data (all tx fields except for calldata) - let padding_txs: Vec<_> = (txs.len()..max_txs) - .map(|i| Transaction { - id: i + 1, - ..Default::default() - }) - .collect(); - for tx in txs.iter().chain(padding_txs.iter()) { - let [tx_data, tx_calldata] = tx.table_assignments(*challenges); - for row in tx_data { - assign_row(&mut region, offset, &advice_columns, &self.tag, &row, "")?; - offset += 1; - } - calldata_assignments.extend(tx_calldata.iter()); - } - // Assign Tx calldata - let padding_calldata = (sum_txs_calldata..max_calldata).map(|_| { - [ - Value::known(F::ZERO), - Value::known(F::from(TxContextFieldTag::CallData as u64)), - Value::known(F::ZERO), - Value::known(F::ZERO), - ] - }); - for row in calldata_assignments.into_iter().chain(padding_calldata) { - assign_row(&mut region, offset, &advice_columns, &self.tag, &row, "")?; - offset += 1; - } - Ok(()) - }, - ) - } -} - -impl LookupTable for TxTable { - fn columns(&self) -> Vec> { - vec![ - self.tx_id.into(), - self.tag.into(), - self.index.into(), - self.value.into(), - ] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("tx_id"), - String::from("tag"), - String::from("index"), - String::from("value"), - ] - } - - fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { - vec![ - meta.query_advice(self.tx_id, Rotation::cur()), - meta.query_fixed(self.tag, Rotation::cur()), - meta.query_advice(self.index, Rotation::cur()), - meta.query_advice(self.value, Rotation::cur()), - ] - } -} - -/// Tag to identify the operation type in a RwTable row -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIter)] -pub enum RwTableTag { - /// Start (used for padding) - Start = 1, - /// Stack operation - Stack, - /// Memory operation - Memory, - /// Account Storage operation - AccountStorage, - /// Tx Access List Account operation - TxAccessListAccount, - /// Tx Access List Account Storage operation - TxAccessListAccountStorage, - /// Tx Refund operation - TxRefund, - /// Account operation - Account, - /// Call Context operation - CallContext, - /// Tx Log operation - TxLog, - /// Tx Receipt operation - TxReceipt, -} -impl_expr!(RwTableTag); - -impl RwTableTag { - /// Returns true if the RwTable operation is reversible - pub fn is_reversible(self) -> bool { - matches!( - self, - RwTableTag::TxAccessListAccount - | RwTableTag::TxAccessListAccountStorage - | RwTableTag::TxRefund - | RwTableTag::Account - | RwTableTag::AccountStorage - ) - } -} - -impl From for usize { - fn from(t: RwTableTag) -> Self { - t as usize - } -} - -impl From for RwTableTag { - fn from(t: Target) -> Self { - match t { - Target::Memory => Self::Memory, - Target::Stack => Self::Stack, - Target::Storage => Self::AccountStorage, - Target::TxAccessListAccount => Self::TxAccessListAccount, - Target::TxAccessListAccountStorage => Self::TxAccessListAccountStorage, - Target::TxRefund => Self::TxRefund, - Target::Account => Self::Account, - Target::CallContext => Self::CallContext, - Target::TxReceipt => Self::TxReceipt, - Target::TxLog => Self::TxLog, - Target::Start => Self::Start, - } - } -} - /// Tag for an AccountField in RwTable #[derive(Clone, Copy, Debug, EnumIter, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum AccountFieldTag { @@ -362,30 +129,6 @@ pub enum AccountFieldTag { } impl_expr!(AccountFieldTag); -/// Tag for a TxLogField in RwTable -#[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter)] -pub enum TxLogFieldTag { - /// Address field - Address = 1, - /// Topic field - Topic, - /// Data field - Data, -} -impl_expr!(TxLogFieldTag); - -/// Tag for a TxReceiptField in RwTable -#[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter, EnumCount)] -pub enum TxReceiptFieldTag { - /// Tx result - PostStateOrStatus = 1, - /// CumulativeGasUsed in the tx - CumulativeGasUsed, - /// Number of logs in the tx - LogLength, -} -impl_expr!(TxReceiptFieldTag); - /// Tag for a CallContextField in RwTable #[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter)] pub enum CallContextFieldTag { @@ -443,1072 +186,3 @@ pub enum CallContextFieldTag { ReversibleWriteCounter, } impl_expr!(CallContextFieldTag); - -/// The RwTable shared between EVM Circuit and State Circuit, which contains -/// traces of the EVM state operations. -#[derive(Clone, Copy, Debug)] -pub struct RwTable { - /// Read Write Counter - pub rw_counter: Column, - /// Is Write - pub is_write: Column, - /// Tag - pub tag: Column, - /// Key1 (Id) - pub id: Column, - /// Key2 (Address) - pub address: Column, - /// Key3 (FieldTag) - pub field_tag: Column, - /// Key3 (StorageKey) - pub storage_key: Column, - /// Value - pub value: Column, - /// Value Previous - pub value_prev: Column, - /// Aux1 - pub aux1: Column, - /// Aux2 (Committed Value) - pub aux2: Column, -} - -impl LookupTable for RwTable { - fn columns(&self) -> Vec> { - vec![ - self.rw_counter.into(), - self.is_write.into(), - self.tag.into(), - self.id.into(), - self.address.into(), - self.field_tag.into(), - self.storage_key.into(), - self.value.into(), - self.value_prev.into(), - self.aux1.into(), - self.aux2.into(), - ] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("rw_counter"), - String::from("is_write"), - String::from("tag"), - String::from("id"), - String::from("address"), - String::from("field_tag"), - String::from("storage_key"), - String::from("value"), - String::from("value_prev"), - String::from("aux1"), - String::from("aux2"), - ] - } -} -impl RwTable { - /// Construct a new RwTable - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - rw_counter: meta.advice_column(), - is_write: meta.advice_column(), - tag: meta.advice_column(), - id: meta.advice_column(), - address: meta.advice_column(), - field_tag: meta.advice_column(), - storage_key: meta.advice_column_in(SecondPhase), - value: meta.advice_column_in(SecondPhase), - value_prev: meta.advice_column_in(SecondPhase), - // It seems that aux1 for the moment is not using randomness - // TODO check in a future review - aux1: meta.advice_column_in(SecondPhase), - aux2: meta.advice_column_in(SecondPhase), - } - } - fn assign( - &self, - region: &mut Region<'_, F>, - offset: usize, - row: &RwRow>, - ) -> Result<(), Error> { - for (column, value) in [ - (self.rw_counter, row.rw_counter), - (self.is_write, row.is_write), - (self.tag, row.tag), - (self.id, row.id), - (self.address, row.address), - (self.field_tag, row.field_tag), - (self.storage_key, row.storage_key), - (self.value, row.value), - (self.value_prev, row.value_prev), - (self.aux1, row.aux1), - (self.aux2, row.aux2), - ] { - region.assign_advice(|| "assign rw row on rw table", column, offset, || value)?; - } - Ok(()) - } - - /// Assign the `RwTable` from a `RwMap`, following the same - /// table layout that the State Circuit uses. - pub fn load( - &self, - layouter: &mut impl Layouter, - rws: &[Rw], - n_rows: usize, - challenges: Value, - ) -> Result<(), Error> { - layouter.assign_region( - || "rw table", - |mut region| self.load_with_region(&mut region, rws, n_rows, challenges), - ) - } - - pub(crate) fn load_with_region( - &self, - region: &mut Region<'_, F>, - rws: &[Rw], - n_rows: usize, - challenges: Value, - ) -> Result<(), Error> { - let (rows, _) = RwMap::table_assignments_prepad(rws, n_rows); - for (offset, row) in rows.iter().enumerate() { - self.assign(region, offset, &row.table_assignment(challenges))?; - } - Ok(()) - } -} - -/// The types of proofs in the MPT table -#[derive(Clone, Copy, Debug)] -pub enum MPTProofType { - /// Nonce updated - NonceMod = AccountFieldTag::Nonce as isize, - /// Balance updated - BalanceMod = AccountFieldTag::Balance as isize, - /// Code hash exists - CodeHashMod = AccountFieldTag::CodeHash as isize, - /// Account does not exist - NonExistingAccountProof = AccountFieldTag::NonExisting as isize, - /// Storage updated - StorageMod, - /// Storage does not exist - NonExistingStorageProof, -} -impl_expr!(MPTProofType); - -impl From for MPTProofType { - fn from(tag: AccountFieldTag) -> Self { - match tag { - AccountFieldTag::Nonce => Self::NonceMod, - AccountFieldTag::Balance => Self::BalanceMod, - AccountFieldTag::CodeHash => Self::CodeHashMod, - AccountFieldTag::NonExisting => Self::NonExistingAccountProof, - } - } -} - -/// The MptTable shared between MPT Circuit and State Circuit -#[derive(Clone, Copy, Debug)] -pub struct MptTable([Column; 7]); - -impl LookupTable for MptTable { - fn columns(&self) -> Vec> { - self.0.iter().map(|&col| col.into()).collect() - } - - fn annotations(&self) -> Vec { - vec![ - String::from("address"), - String::from("storage_key"), - String::from("proof_type"), - String::from("new_root"), - String::from("old_root"), - String::from("new_value"), - String::from("old_value"), - ] - } -} - -impl MptTable { - /// Construct a new MptTable - pub(crate) fn construct(meta: &mut ConstraintSystem) -> Self { - Self([ - meta.advice_column(), // Address - meta.advice_column_in(SecondPhase), // Storage key - meta.advice_column(), // Proof type - meta.advice_column_in(SecondPhase), // New root - meta.advice_column_in(SecondPhase), // Old root - meta.advice_column_in(SecondPhase), // New value - meta.advice_column_in(SecondPhase), // Old value - ]) - } - - pub(crate) fn assign( - &self, - region: &mut Region<'_, F>, - offset: usize, - row: &MptUpdateRow>, - ) -> Result<(), Error> { - for (column, value) in self.0.iter().zip_eq(row.values()) { - region.assign_advice(|| "assign mpt table row value", *column, offset, || *value)?; - } - Ok(()) - } - - pub(crate) fn load( - &self, - layouter: &mut impl Layouter, - updates: &MptUpdates, - randomness: Value, - ) -> Result<(), Error> { - layouter.assign_region( - || "mpt table", - |mut region| self.load_with_region(&mut region, updates, randomness), - ) - } - - pub(crate) fn load_with_region( - &self, - region: &mut Region<'_, F>, - updates: &MptUpdates, - randomness: Value, - ) -> Result<(), Error> { - for (offset, row) in updates.table_assignments(randomness).iter().enumerate() { - self.assign(region, offset, row)?; - } - Ok(()) - } -} - -/// Tag to identify the field in a Bytecode Table row -#[derive(Clone, Copy, Debug)] -pub enum BytecodeFieldTag { - /// Header field - Header, - /// Byte field - Byte, -} -impl_expr!(BytecodeFieldTag); - -/// Table with Bytecode indexed by its Code Hash -#[derive(Clone, Debug)] -pub struct BytecodeTable { - /// Code Hash - pub code_hash: Column, - /// Tag - pub tag: Column, - /// Index - pub index: Column, - /// Is Code is true when the byte is not an argument to a PUSH* instruction. - pub is_code: Column, - /// Value - pub value: Column, -} - -impl BytecodeTable { - /// Construct a new BytecodeTable - pub fn construct(meta: &mut ConstraintSystem) -> Self { - let [tag, index, is_code, value] = array::from_fn(|_| meta.advice_column()); - let code_hash = meta.advice_column_in(SecondPhase); - Self { - code_hash, - tag, - index, - is_code, - value, - } - } - - /// Assign the `BytecodeTable` from a list of bytecodes, followig the same - /// table layout that the Bytecode Circuit uses. - pub fn load<'a, F: Field>( - &self, - layouter: &mut impl Layouter, - bytecodes: impl IntoIterator + Clone, - challenges: &Challenges>, - ) -> Result<(), Error> { - layouter.assign_region( - || "bytecode table", - |mut region| { - let mut offset = 0; - for column in >::advice_columns(self) { - region.assign_advice( - || "bytecode table all-zero row", - column, - offset, - || Value::known(F::ZERO), - )?; - } - offset += 1; - - let bytecode_table_columns = - >::advice_columns(self); - for bytecode in bytecodes.clone() { - for row in bytecode.table_assignments(challenges) { - for (&column, value) in bytecode_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("bytecode table row {}", offset), - column, - offset, - || value, - )?; - } - offset += 1; - } - } - Ok(()) - }, - ) - } -} - -impl LookupTable for BytecodeTable { - fn columns(&self) -> Vec> { - vec![ - self.code_hash.into(), - self.tag.into(), - self.index.into(), - self.is_code.into(), - self.value.into(), - ] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("code_hash"), - String::from("tag"), - String::from("index"), - String::from("is_code"), - String::from("value"), - ] - } -} - -/// Tag to identify the field in a Block Table row -// Keep the sequence consistent with OpcodeId for scalar -#[derive(Clone, Copy, Debug)] -pub enum BlockContextFieldTag { - /// Coinbase field - Coinbase = 1, - /// Timestamp field - Timestamp, - /// Number field - Number, - /// Difficulty field - Difficulty, - /// Gas Limit field - GasLimit, - /// Base Fee field - BaseFee = 8, - /// Block Hash field - BlockHash, - /// Chain ID field. Although this is not a field in the block header, we - /// add it here for convenience. - ChainId, -} -impl_expr!(BlockContextFieldTag); - -/// Table with Block header fields -#[derive(Clone, Debug)] -pub struct BlockTable { - /// Tag - pub tag: Column, - /// Index - pub index: Column, - /// Value - pub value: Column, -} - -impl BlockTable { - /// Construct a new BlockTable - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - tag: meta.advice_column(), - index: meta.advice_column(), - value: meta.advice_column_in(SecondPhase), - } - } - - /// Assign the `BlockTable` from a `BlockContext`. - pub fn load( - &self, - layouter: &mut impl Layouter, - block: &BlockContext, - randomness: Value, - ) -> Result<(), Error> { - layouter.assign_region( - || "block table", - |mut region| { - let mut offset = 0; - for column in >::advice_columns(self) { - region.assign_advice( - || "block table all-zero row", - column, - offset, - || Value::known(F::ZERO), - )?; - } - offset += 1; - - let block_table_columns = >::advice_columns(self); - for row in block.table_assignments(randomness) { - for (&column, value) in block_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("block table row {}", offset), - column, - offset, - || value, - )?; - } - offset += 1; - } - - Ok(()) - }, - ) - } -} - -impl LookupTable for BlockTable { - fn columns(&self) -> Vec> { - vec![self.tag.into(), self.index.into(), self.value.into()] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("tag"), - String::from("index"), - String::from("value"), - ] - } -} - -/// Keccak Table, used to verify keccak hashing from RLC'ed input. -#[derive(Clone, Debug)] -pub struct KeccakTable { - /// True when the row is enabled - pub is_enabled: Column, - /// Byte array input as `RLC(reversed(input))` - pub input_rlc: Column, // RLC of input bytes - /// Byte array input length - pub input_len: Column, - /// RLC of the hash result - pub output_rlc: Column, // RLC of hash of input bytes -} - -impl LookupTable for KeccakTable { - fn columns(&self) -> Vec> { - vec![ - self.is_enabled.into(), - self.input_rlc.into(), - self.input_len.into(), - self.output_rlc.into(), - ] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("is_enabled"), - String::from("input_rlc"), - String::from("input_len"), - String::from("output_rlc"), - ] - } -} - -impl KeccakTable { - /// Construct a new KeccakTable - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - is_enabled: meta.advice_column(), - input_rlc: meta.advice_column_in(SecondPhase), - input_len: meta.advice_column(), - output_rlc: meta.advice_column_in(SecondPhase), - } - } - - /// Generate the keccak table assignments from a byte array input. - pub fn assignments( - input: &[u8], - challenges: &Challenges>, - ) -> Vec<[Value; 4]> { - let input_rlc = challenges - .keccak_input() - .map(|challenge| rlc::value(input.iter().rev(), challenge)); - let input_len = F::from(input.len() as u64); - let mut keccak = Keccak::default(); - keccak.update(input); - let output = keccak.digest(); - let output_rlc = challenges.evm_word().map(|challenge| { - rlc::value( - &Word::from_big_endian(output.as_slice()).to_le_bytes(), - challenge, - ) - }); - - vec![[ - Value::known(F::ONE), - input_rlc, - Value::known(input_len), - output_rlc, - ]] - } - - /// Assign a table row for keccak table - pub fn assign_row( - &self, - region: &mut Region, - offset: usize, - values: [Value; 4], - ) -> Result<(), Error> { - for (&column, value) in >::advice_columns(self) - .iter() - .zip(values.iter()) - { - region.assign_advice(|| format!("assign {}", offset), column, offset, || *value)?; - } - Ok(()) - } - - /// Provide this function for the case that we want to consume a keccak - /// table but without running the full keccak circuit - pub fn dev_load<'a, F: Field>( - &self, - layouter: &mut impl Layouter, - inputs: impl IntoIterator> + Clone, - challenges: &Challenges>, - ) -> Result<(), Error> { - layouter.assign_region( - || "keccak table", - |mut region| { - let mut offset = 0; - for column in >::advice_columns(self) { - region.assign_advice( - || "keccak table all-zero row", - column, - offset, - || Value::known(F::ZERO), - )?; - } - offset += 1; - - let keccak_table_columns = >::advice_columns(self); - for input in inputs.clone() { - for row in Self::assignments(input, challenges) { - // let mut column_index = 0; - for (&column, value) in keccak_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("keccak table row {}", offset), - column, - offset, - || value, - )?; - } - offset += 1; - } - } - Ok(()) - }, - ) - } - - /// returns matchings between the circuit columns passed as parameters and - /// the table collumns - pub fn match_columns( - &self, - value_rlc: Column, - length: Column, - code_hash: Column, - ) -> Vec<(Column, Column)> { - vec![ - (value_rlc, self.input_rlc), - (length, self.input_len), - (code_hash, self.output_rlc), - ] - } -} - -/// Copy Table, used to verify copies of byte chunks between Memory, Bytecode, -/// TxLogs and TxCallData. -#[derive(Clone, Copy, Debug)] -pub struct CopyTable { - /// Whether the row is the first read-write pair for a copy event. - pub is_first: Column, - /// The relevant ID for the read-write row, represented as a random linear - /// combination. The ID may be one of the below: - /// 1. Call ID/Caller ID for CopyDataType::Memory - /// 2. RLC encoding of bytecode hash for CopyDataType::Bytecode - /// 3. Transaction ID for CopyDataType::TxCalldata, CopyDataType::TxLog - pub id: Column, - /// The source/destination address for this copy step. Can be memory - /// address, byte index in the bytecode, tx call data, and tx log data. - pub addr: Column, - /// The end of the source buffer for the copy event. Any data read from an - /// address greater than or equal to this value will be 0. - pub src_addr_end: Column, - /// The number of bytes left to be copied. - pub bytes_left: Column, - /// An accumulator value in the RLC representation. This is used for - /// specific purposes, for instance, when `tag == CopyDataType::RlcAcc`. - /// Having an additional column for the `rlc_acc` simplifies the lookup - /// to copy table. - pub rlc_acc: Column, - /// The associated read-write counter for this row. - pub rw_counter: Column, - /// Decrementing counter denoting reverse read-write counter. - pub rwc_inc_left: Column, - /// Binary chip to constrain the copy table conditionally depending on the - /// current row's tag, whether it is Bytecode, Memory, TxCalldata or - /// TxLog. - pub tag: BinaryNumberConfig, -} - -type CopyTableRow = [(Value, &'static str); 8]; -type CopyCircuitRow = [(Value, &'static str); 4]; - -impl CopyTable { - /// Construct a new CopyTable - pub fn construct(meta: &mut ConstraintSystem, q_enable: Column) -> Self { - Self { - is_first: meta.advice_column(), - id: meta.advice_column_in(SecondPhase), - tag: BinaryNumberChip::configure(meta, q_enable, None), - addr: meta.advice_column(), - src_addr_end: meta.advice_column(), - bytes_left: meta.advice_column(), - rlc_acc: meta.advice_column_in(SecondPhase), - rw_counter: meta.advice_column(), - rwc_inc_left: meta.advice_column(), - } - } - - /// Generate the copy table and copy circuit assignments from a copy event. - pub fn assignments( - copy_event: &CopyEvent, - challenges: Challenges>, - ) -> Vec<(CopyDataType, CopyTableRow, CopyCircuitRow)> { - let mut assignments = Vec::new(); - // rlc_acc - let rlc_acc = if copy_event.dst_type == CopyDataType::RlcAcc { - let values = copy_event - .bytes - .iter() - .map(|(value, _)| *value) - .collect::>(); - challenges - .keccak_input() - .map(|keccak_input| rlc::value(values.iter().rev(), keccak_input)) - } else { - Value::known(F::ZERO) - }; - let mut value_acc = Value::known(F::ZERO); - for (step_idx, (is_read_step, copy_step)) in copy_event - .bytes - .iter() - .flat_map(|(value, is_code)| { - let read_step = CopyStep { - value: *value, - is_code: if copy_event.src_type == CopyDataType::Bytecode { - Some(*is_code) - } else { - None - }, - }; - let write_step = CopyStep { - value: *value, - is_code: if copy_event.dst_type == CopyDataType::Bytecode { - Some(*is_code) - } else { - None - }, - }; - once((true, read_step)).chain(once((false, write_step))) - }) - .enumerate() - { - // is_first - let is_first = Value::known(if step_idx == 0 { F::ONE } else { F::ZERO }); - // is last - let is_last = if step_idx == copy_event.bytes.len() * 2 - 1 { - Value::known(F::ONE) - } else { - Value::known(F::ZERO) - }; - - // id - let id = if is_read_step { - number_or_hash_to_field(©_event.src_id, challenges.evm_word()) - } else { - number_or_hash_to_field(©_event.dst_id, challenges.evm_word()) - }; - - // tag binary bumber chip - let tag = if is_read_step { - copy_event.src_type - } else { - copy_event.dst_type - }; - - // addr - let copy_step_addr: u64 = - if is_read_step { - copy_event.src_addr - } else { - copy_event.dst_addr - } + (u64::try_from(step_idx).unwrap() - if is_read_step { 0 } else { 1 }) / 2u64; - - let addr = if tag == CopyDataType::TxLog { - Value::known( - build_tx_log_address( - copy_step_addr, - TxLogFieldTag::Data, - copy_event.log_id.unwrap(), - ) - .to_scalar() - .unwrap(), - ) - } else { - Value::known(F::from(copy_step_addr)) - }; - - // bytes_left - let bytes_left = u64::try_from(copy_event.bytes.len() * 2 - step_idx).unwrap() / 2; - // value - let value = if copy_event.dst_type == CopyDataType::RlcAcc { - if is_read_step { - Value::known(F::from(copy_step.value as u64)) - } else { - value_acc = value_acc * challenges.keccak_input() - + Value::known(F::from(copy_step.value as u64)); - value_acc - } - } else { - Value::known(F::from(copy_step.value as u64)) - }; - // is_pad - let is_pad = Value::known(F::from( - (is_read_step && copy_step_addr >= copy_event.src_addr_end) as u64, - )); - - // is_code - let is_code = Value::known(copy_step.is_code.map_or(F::ZERO, |v| F::from(v as u64))); - - assignments.push(( - tag, - [ - (is_first, "is_first"), - (id, "id"), - (addr, "addr"), - ( - Value::known(F::from(copy_event.src_addr_end)), - "src_addr_end", - ), - (Value::known(F::from(bytes_left)), "bytes_left"), - (rlc_acc, "rlc_acc"), - ( - Value::known(F::from(copy_event.rw_counter(step_idx))), - "rw_counter", - ), - ( - Value::known(F::from(copy_event.rw_counter_increase_left(step_idx))), - "rwc_inc_left", - ), - ], - [ - (is_last, "is_last"), - (value, "value"), - (is_pad, "is_pad"), - (is_code, "is_code"), - ], - )); - } - assignments - } - - /// Assign the `CopyTable` from a `Block`. - pub fn load( - &self, - layouter: &mut impl Layouter, - block: &Block, - challenges: &Challenges>, - ) -> Result<(), Error> { - layouter.assign_region( - || "copy table", - |mut region| { - let mut offset = 0; - for column in >::advice_columns(self) { - region.assign_advice( - || "copy table all-zero row", - column, - offset, - || Value::known(F::ZERO), - )?; - } - offset += 1; - - let tag_chip = BinaryNumberChip::construct(self.tag); - let copy_table_columns = >::advice_columns(self); - for copy_event in block.copy_events.iter() { - for (tag, row, _) in Self::assignments(copy_event, *challenges) { - for (&column, (value, label)) in copy_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("{} at row: {}", label, offset), - column, - offset, - || value, - )?; - } - tag_chip.assign(&mut region, offset, &tag)?; - offset += 1; - } - } - - Ok(()) - }, - ) - } -} - -impl LookupTable for CopyTable { - fn columns(&self) -> Vec> { - vec![ - self.is_first.into(), - self.id.into(), - self.addr.into(), - self.src_addr_end.into(), - self.bytes_left.into(), - self.rlc_acc.into(), - self.rw_counter.into(), - self.rwc_inc_left.into(), - ] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("is_first"), - String::from("id"), - String::from("addr"), - String::from("src_addr_end"), - String::from("bytes_left"), - String::from("rlc_acc"), - String::from("rw_counter"), - String::from("rwc_inc_left"), - ] - } - - fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { - vec![ - meta.query_advice(self.is_first, Rotation::cur()), - meta.query_advice(self.id, Rotation::cur()), // src_id - self.tag.value(Rotation::cur())(meta), // src_tag - meta.query_advice(self.id, Rotation::next()), // dst_id - self.tag.value(Rotation::next())(meta), // dst_tag - meta.query_advice(self.addr, Rotation::cur()), // src_addr - meta.query_advice(self.src_addr_end, Rotation::cur()), // src_addr_end - meta.query_advice(self.addr, Rotation::next()), // dst_addr - meta.query_advice(self.bytes_left, Rotation::cur()), // length - meta.query_advice(self.rlc_acc, Rotation::cur()), // rlc_acc - meta.query_advice(self.rw_counter, Rotation::cur()), // rw_counter - meta.query_advice(self.rwc_inc_left, Rotation::cur()), // rwc_inc_left - ] - } -} - -/// Lookup table within the Exponentiation circuit. -#[derive(Clone, Copy, Debug)] -pub struct ExpTable { - /// Whether the row is the start of a step. - pub is_step: Column, - /// An identifier for every exponentiation trace, at the moment this is the - /// read-write counter at the time of the lookups done to the - /// exponentiation table. - pub identifier: Column, - /// Whether this row is the last row in the exponentiation operation's - /// trace. - pub is_last: Column, - /// The integer base of the exponentiation. - pub base_limb: Column, - /// The integer exponent of the exponentiation. - pub exponent_lo_hi: Column, - /// The intermediate result of exponentiation by squaring. - pub exponentiation_lo_hi: Column, -} - -impl ExpTable { - /// Construct the Exponentiation table. - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - is_step: meta.fixed_column(), - identifier: meta.advice_column(), - is_last: meta.advice_column(), - base_limb: meta.advice_column(), - exponent_lo_hi: meta.advice_column(), - exponentiation_lo_hi: meta.advice_column(), - } - } - - /// Given an exponentiation event and randomness, get assignments to the - /// exponentiation table. - pub fn assignments(exp_event: &ExpEvent) -> Vec<[F; 5]> { - let mut assignments = Vec::new(); - let base_limbs = split_u256_limb64(&exp_event.base); - let identifier = F::from(exp_event.identifier as u64); - let mut exponent = exp_event.exponent; - for (step_idx, exp_step) in exp_event.steps.iter().rev().enumerate() { - let is_last = if step_idx == exp_event.steps.len() - 1 { - F::ONE - } else { - F::ZERO - }; - let (exp_lo, exp_hi) = split_u256(&exp_step.d); - let (exponent_lo, exponent_hi) = split_u256(&exponent); - - // row 1 - assignments.push([ - identifier, - is_last, - base_limbs[0].as_u64().into(), - exponent_lo - .to_scalar() - .expect("exponent should fit to scalar"), - exp_lo - .to_scalar() - .expect("exponentiation lo should fit to scalar"), - ]); - // row 2 - assignments.push([ - identifier, - F::ZERO, - base_limbs[1].as_u64().into(), - exponent_hi - .to_scalar() - .expect("exponent hi should fit to scalar"), - exp_hi - .to_scalar() - .expect("exponentiation hi should fit to scalar"), - ]); - // row 3 - assignments.push([ - identifier, - F::ZERO, - base_limbs[2].as_u64().into(), - F::ZERO, - F::ZERO, - ]); - // row 4 - assignments.push([ - identifier, - F::ZERO, - base_limbs[3].as_u64().into(), - F::ZERO, - F::ZERO, - ]); - for _ in ROWS_PER_STEP..OFFSET_INCREMENT { - assignments.push([F::ZERO, F::ZERO, F::ZERO, F::ZERO, F::ZERO]); - } - - // update intermediate exponent. - let (exponent_div2, remainder) = exponent.div_mod(U256::from(2)); - if remainder.is_zero() { - // exponent is even - exponent = exponent_div2; - } else { - // exponent is odd - exponent = exponent - 1; - } - } - assignments - } - - /// Assign witness data from a block to the exponentiation table. - pub fn load( - &self, - layouter: &mut impl Layouter, - block: &Block, - ) -> Result<(), Error> { - layouter.assign_region( - || "exponentiation table", - |mut region| { - let mut offset = 0; - let exp_table_columns = >::advice_columns(self); - for exp_event in block.exp_events.iter() { - for row in Self::assignments::(exp_event) { - for (&column, value) in exp_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("exponentiation table row {}", offset), - column, - offset, - || Value::known(value), - )?; - } - let is_step = if offset % OFFSET_INCREMENT == 0 { - F::ONE - } else { - F::ZERO - }; - region.assign_fixed( - || format!("exponentiation table row {}", offset), - self.is_step, - offset, - || Value::known(is_step), - )?; - offset += 1; - } - } - - // pad an empty row - let row = [F::from_u128(0); 5]; - for (column, value) in exp_table_columns.iter().zip_eq(row) { - region.assign_advice( - || format!("exponentiation table row {}", offset), - *column, - offset, - || Value::known(value), - )?; - } - - Ok(()) - }, - ) - } -} - -impl LookupTable for ExpTable { - fn columns(&self) -> Vec> { - vec![ - self.is_step.into(), - self.identifier.into(), - self.is_last.into(), - self.base_limb.into(), - self.exponent_lo_hi.into(), - self.exponentiation_lo_hi.into(), - ] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("is_step"), - String::from("identifier"), - String::from("is_last"), - String::from("base_limb"), - String::from("exponent_lo_hi"), - String::from("exponentiation_lo_hi"), - ] - } - - fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { - vec![ - meta.query_fixed(self.is_step, Rotation::cur()), - meta.query_advice(self.identifier, Rotation::cur()), - meta.query_advice(self.is_last, Rotation::cur()), - meta.query_advice(self.base_limb, Rotation::cur()), - meta.query_advice(self.base_limb, Rotation::next()), - meta.query_advice(self.base_limb, Rotation(2)), - meta.query_advice(self.base_limb, Rotation(3)), - meta.query_advice(self.exponent_lo_hi, Rotation::cur()), - meta.query_advice(self.exponent_lo_hi, Rotation::next()), - meta.query_advice(self.exponentiation_lo_hi, Rotation::cur()), - meta.query_advice(self.exponentiation_lo_hi, Rotation::next()), - ] - } -} diff --git a/zkevm-circuits/src/table/block_table.rs b/zkevm-circuits/src/table/block_table.rs new file mode 100644 index 0000000000..443e993673 --- /dev/null +++ b/zkevm-circuits/src/table/block_table.rs @@ -0,0 +1,100 @@ +use super::*; + +/// Tag to identify the field in a Block Table row +// Keep the sequence consistent with OpcodeId for scalar +#[derive(Clone, Copy, Debug)] +pub enum BlockContextFieldTag { + /// Coinbase field + Coinbase = 1, + /// Timestamp field + Timestamp, + /// Number field + Number, + /// Difficulty field + Difficulty, + /// Gas Limit field + GasLimit, + /// Base Fee field + BaseFee = 8, + /// Block Hash field + BlockHash, + /// Chain ID field. Although this is not a field in the block header, we + /// add it here for convenience. + ChainId, +} +impl_expr!(BlockContextFieldTag); + +/// Table with Block header fields +#[derive(Clone, Debug)] +pub struct BlockTable { + /// Tag + pub tag: Column, + /// Index + pub index: Column, + /// Value + pub value: Column, +} + +impl BlockTable { + /// Construct a new BlockTable + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + tag: meta.advice_column(), + index: meta.advice_column(), + value: meta.advice_column_in(SecondPhase), + } + } + + /// Assign the `BlockTable` from a `BlockContext`. + pub fn load( + &self, + layouter: &mut impl Layouter, + block: &BlockContext, + randomness: Value, + ) -> Result<(), Error> { + layouter.assign_region( + || "block table", + |mut region| { + let mut offset = 0; + for column in >::advice_columns(self) { + region.assign_advice( + || "block table all-zero row", + column, + offset, + || Value::known(F::ZERO), + )?; + } + offset += 1; + + let block_table_columns = >::advice_columns(self); + for row in block.table_assignments(randomness) { + for (&column, value) in block_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("block table row {}", offset), + column, + offset, + || value, + )?; + } + offset += 1; + } + + Ok(()) + }, + ) + } +} + +impl LookupTable for BlockTable { + fn columns(&self) -> Vec> { + vec![self.tag.into(), self.index.into(), self.value.into()] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("tag"), + String::from("index"), + String::from("value"), + ] + } +} diff --git a/zkevm-circuits/src/table/bytecode_table.rs b/zkevm-circuits/src/table/bytecode_table.rs new file mode 100644 index 0000000000..2b6a8a5d27 --- /dev/null +++ b/zkevm-circuits/src/table/bytecode_table.rs @@ -0,0 +1,105 @@ +use super::*; + +/// Tag to identify the field in a Bytecode Table row +#[derive(Clone, Copy, Debug)] +pub enum BytecodeFieldTag { + /// Header field + Header, + /// Byte field + Byte, +} +impl_expr!(BytecodeFieldTag); + +/// Table with Bytecode indexed by its Code Hash +#[derive(Clone, Debug)] +pub struct BytecodeTable { + /// Code Hash + pub code_hash: Column, + /// Tag + pub tag: Column, + /// Index + pub index: Column, + /// Is Code is true when the byte is not an argument to a PUSH* instruction. + pub is_code: Column, + /// Value + pub value: Column, +} + +impl BytecodeTable { + /// Construct a new BytecodeTable + pub fn construct(meta: &mut ConstraintSystem) -> Self { + let [tag, index, is_code, value] = array::from_fn(|_| meta.advice_column()); + let code_hash = meta.advice_column_in(SecondPhase); + Self { + code_hash, + tag, + index, + is_code, + value, + } + } + + /// Assign the `BytecodeTable` from a list of bytecodes, followig the same + /// table layout that the Bytecode Circuit uses. + pub fn load<'a, F: Field>( + &self, + layouter: &mut impl Layouter, + bytecodes: impl IntoIterator + Clone, + challenges: &Challenges>, + ) -> Result<(), Error> { + layouter.assign_region( + || "bytecode table", + |mut region| { + let mut offset = 0; + for column in >::advice_columns(self) { + region.assign_advice( + || "bytecode table all-zero row", + column, + offset, + || Value::known(F::ZERO), + )?; + } + offset += 1; + + let bytecode_table_columns = + >::advice_columns(self); + for bytecode in bytecodes.clone() { + for row in bytecode.table_assignments(challenges) { + for (&column, value) in bytecode_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("bytecode table row {}", offset), + column, + offset, + || value, + )?; + } + offset += 1; + } + } + Ok(()) + }, + ) + } +} + +impl LookupTable for BytecodeTable { + fn columns(&self) -> Vec> { + vec![ + self.code_hash.into(), + self.tag.into(), + self.index.into(), + self.is_code.into(), + self.value.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("code_hash"), + String::from("tag"), + String::from("index"), + String::from("is_code"), + String::from("value"), + ] + } +} diff --git a/zkevm-circuits/src/table/copy_table.rs b/zkevm-circuits/src/table/copy_table.rs new file mode 100644 index 0000000000..86ad806df9 --- /dev/null +++ b/zkevm-circuits/src/table/copy_table.rs @@ -0,0 +1,304 @@ +use super::*; + +// use crate::{ +// table::LookupTable, +// witness::Block, +// }; +// use bus_mapping::circuit_input_builder::ExpEvent; +// use eth_types::{Field, ToScalar, U256}; +// use halo2_proofs::{ +// circuit::{Layouter, Region, Value}, +// plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, +// poly::Rotation, +// }; +// use itertools::Itertools; +// use gadgets::{ +// binary_number::{BinaryNumberChip, BinaryNumberConfig}, +// util::{split_u256, split_u256_limb64}, +// }; + +type CopyTableRow = [(Value, &'static str); 8]; +type CopyCircuitRow = [(Value, &'static str); 4]; + +/// Copy Table, used to verify copies of byte chunks between Memory, Bytecode, +/// TxLogs and TxCallData. +#[derive(Clone, Copy, Debug)] +pub struct CopyTable { + /// Whether the row is the first read-write pair for a copy event. + pub is_first: Column, + /// The relevant ID for the read-write row, represented as a random linear + /// combination. The ID may be one of the below: + /// 1. Call ID/Caller ID for CopyDataType::Memory + /// 2. RLC encoding of bytecode hash for CopyDataType::Bytecode + /// 3. Transaction ID for CopyDataType::TxCalldata, CopyDataType::TxLog + pub id: Column, + /// The source/destination address for this copy step. Can be memory + /// address, byte index in the bytecode, tx call data, and tx log data. + pub addr: Column, + /// The end of the source buffer for the copy event. Any data read from an + /// address greater than or equal to this value will be 0. + pub src_addr_end: Column, + /// The number of bytes left to be copied. + pub bytes_left: Column, + /// An accumulator value in the RLC representation. This is used for + /// specific purposes, for instance, when `tag == CopyDataType::RlcAcc`. + /// Having an additional column for the `rlc_acc` simplifies the lookup + /// to copy table. + pub rlc_acc: Column, + /// The associated read-write counter for this row. + pub rw_counter: Column, + /// Decrementing counter denoting reverse read-write counter. + pub rwc_inc_left: Column, + /// Binary chip to constrain the copy table conditionally depending on the + /// current row's tag, whether it is Bytecode, Memory, TxCalldata or + /// TxLog. + pub tag: BinaryNumberConfig, +} + +impl CopyTable { + /// Construct a new CopyTable + pub fn construct(meta: &mut ConstraintSystem, q_enable: Column) -> Self { + Self { + is_first: meta.advice_column(), + id: meta.advice_column_in(SecondPhase), + tag: BinaryNumberChip::configure(meta, q_enable, None), + addr: meta.advice_column(), + src_addr_end: meta.advice_column(), + bytes_left: meta.advice_column(), + rlc_acc: meta.advice_column_in(SecondPhase), + rw_counter: meta.advice_column(), + rwc_inc_left: meta.advice_column(), + } + } + + /// Generate the copy table and copy circuit assignments from a copy event. + pub fn assignments( + copy_event: &CopyEvent, + challenges: Challenges>, + ) -> Vec<(CopyDataType, CopyTableRow, CopyCircuitRow)> { + let mut assignments = Vec::new(); + // rlc_acc + let rlc_acc = if copy_event.dst_type == CopyDataType::RlcAcc { + let values = copy_event + .bytes + .iter() + .map(|(value, _)| *value) + .collect::>(); + challenges + .keccak_input() + .map(|keccak_input| rlc::value(values.iter().rev(), keccak_input)) + } else { + Value::known(F::ZERO) + }; + let mut value_acc = Value::known(F::ZERO); + for (step_idx, (is_read_step, copy_step)) in copy_event + .bytes + .iter() + .flat_map(|(value, is_code)| { + let read_step = CopyStep { + value: *value, + is_code: if copy_event.src_type == CopyDataType::Bytecode { + Some(*is_code) + } else { + None + }, + }; + let write_step = CopyStep { + value: *value, + is_code: if copy_event.dst_type == CopyDataType::Bytecode { + Some(*is_code) + } else { + None + }, + }; + once((true, read_step)).chain(once((false, write_step))) + }) + .enumerate() + { + // is_first + let is_first = Value::known(if step_idx == 0 { F::ONE } else { F::ZERO }); + // is last + let is_last = if step_idx == copy_event.bytes.len() * 2 - 1 { + Value::known(F::ONE) + } else { + Value::known(F::ZERO) + }; + + // id + let id = if is_read_step { + number_or_hash_to_field(©_event.src_id, challenges.evm_word()) + } else { + number_or_hash_to_field(©_event.dst_id, challenges.evm_word()) + }; + + // tag binary bumber chip + let tag = if is_read_step { + copy_event.src_type + } else { + copy_event.dst_type + }; + + // addr + let copy_step_addr: u64 = + if is_read_step { + copy_event.src_addr + } else { + copy_event.dst_addr + } + (u64::try_from(step_idx).unwrap() - if is_read_step { 0 } else { 1 }) / 2u64; + + let addr = if tag == CopyDataType::TxLog { + Value::known( + build_tx_log_address( + copy_step_addr, + TxLogFieldTag::Data, + copy_event.log_id.unwrap(), + ) + .to_scalar() + .unwrap(), + ) + } else { + Value::known(F::from(copy_step_addr)) + }; + + // bytes_left + let bytes_left = u64::try_from(copy_event.bytes.len() * 2 - step_idx).unwrap() / 2; + // value + let value = if copy_event.dst_type == CopyDataType::RlcAcc { + if is_read_step { + Value::known(F::from(copy_step.value as u64)) + } else { + value_acc = value_acc * challenges.keccak_input() + + Value::known(F::from(copy_step.value as u64)); + value_acc + } + } else { + Value::known(F::from(copy_step.value as u64)) + }; + // is_pad + let is_pad = Value::known(F::from( + (is_read_step && copy_step_addr >= copy_event.src_addr_end) as u64, + )); + + // is_code + let is_code = Value::known(copy_step.is_code.map_or(F::ZERO, |v| F::from(v as u64))); + + assignments.push(( + tag, + [ + (is_first, "is_first"), + (id, "id"), + (addr, "addr"), + ( + Value::known(F::from(copy_event.src_addr_end)), + "src_addr_end", + ), + (Value::known(F::from(bytes_left)), "bytes_left"), + (rlc_acc, "rlc_acc"), + ( + Value::known(F::from(copy_event.rw_counter(step_idx))), + "rw_counter", + ), + ( + Value::known(F::from(copy_event.rw_counter_increase_left(step_idx))), + "rwc_inc_left", + ), + ], + [ + (is_last, "is_last"), + (value, "value"), + (is_pad, "is_pad"), + (is_code, "is_code"), + ], + )); + } + assignments + } + + /// Assign the `CopyTable` from a `Block`. + pub fn load( + &self, + layouter: &mut impl Layouter, + block: &Block, + challenges: &Challenges>, + ) -> Result<(), Error> { + layouter.assign_region( + || "copy table", + |mut region| { + let mut offset = 0; + for column in >::advice_columns(self) { + region.assign_advice( + || "copy table all-zero row", + column, + offset, + || Value::known(F::ZERO), + )?; + } + offset += 1; + + let tag_chip = BinaryNumberChip::construct(self.tag); + let copy_table_columns = >::advice_columns(self); + for copy_event in block.copy_events.iter() { + for (tag, row, _) in Self::assignments(copy_event, *challenges) { + for (&column, (value, label)) in copy_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("{} at row: {}", label, offset), + column, + offset, + || value, + )?; + } + tag_chip.assign(&mut region, offset, &tag)?; + offset += 1; + } + } + + Ok(()) + }, + ) + } +} + +impl LookupTable for CopyTable { + fn columns(&self) -> Vec> { + vec![ + self.is_first.into(), + self.id.into(), + self.addr.into(), + self.src_addr_end.into(), + self.bytes_left.into(), + self.rlc_acc.into(), + self.rw_counter.into(), + self.rwc_inc_left.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("is_first"), + String::from("id"), + String::from("addr"), + String::from("src_addr_end"), + String::from("bytes_left"), + String::from("rlc_acc"), + String::from("rw_counter"), + String::from("rwc_inc_left"), + ] + } + + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + vec![ + meta.query_advice(self.is_first, Rotation::cur()), + meta.query_advice(self.id, Rotation::cur()), // src_id + self.tag.value(Rotation::cur())(meta), // src_tag + meta.query_advice(self.id, Rotation::next()), // dst_id + self.tag.value(Rotation::next())(meta), // dst_tag + meta.query_advice(self.addr, Rotation::cur()), // src_addr + meta.query_advice(self.src_addr_end, Rotation::cur()), // src_addr_end + meta.query_advice(self.addr, Rotation::next()), // dst_addr + meta.query_advice(self.bytes_left, Rotation::cur()), // length + meta.query_advice(self.rlc_acc, Rotation::cur()), // rlc_acc + meta.query_advice(self.rw_counter, Rotation::cur()), // rw_counter + meta.query_advice(self.rwc_inc_left, Rotation::cur()), // rwc_inc_left + ] + } +} diff --git a/zkevm-circuits/src/table/exp_table.rs b/zkevm-circuits/src/table/exp_table.rs new file mode 100644 index 0000000000..f47dca99a3 --- /dev/null +++ b/zkevm-circuits/src/table/exp_table.rs @@ -0,0 +1,215 @@ +use super::*; + +use crate::{ + exp_circuit::param::{OFFSET_INCREMENT, ROWS_PER_STEP}, + table::LookupTable, + witness::Block, +}; +use bus_mapping::circuit_input_builder::ExpEvent; +// use eth_types::{Field, ToScalar, U256}; +// use gadgets::util::{split_u256, split_u256_limb64}; +// use halo2_proofs::{ +// circuit::{Layouter, Region, Value}, +// plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, +// poly::Rotation, +// }; +// use itertools::Itertools; + +/// Lookup table within the Exponentiation circuit. +#[derive(Clone, Copy, Debug)] +pub struct ExpTable { + /// Whether the row is the start of a step. + pub is_step: Column, + /// An identifier for every exponentiation trace, at the moment this is the + /// read-write counter at the time of the lookups done to the + /// exponentiation table. + pub identifier: Column, + /// Whether this row is the last row in the exponentiation operation's + /// trace. + pub is_last: Column, + /// The integer base of the exponentiation. + pub base_limb: Column, + /// The integer exponent of the exponentiation. + pub exponent_lo_hi: Column, + /// The intermediate result of exponentiation by squaring. + pub exponentiation_lo_hi: Column, +} + +impl ExpTable { + /// Construct the Exponentiation table. + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + is_step: meta.fixed_column(), + identifier: meta.advice_column(), + is_last: meta.advice_column(), + base_limb: meta.advice_column(), + exponent_lo_hi: meta.advice_column(), + exponentiation_lo_hi: meta.advice_column(), + } + } + + /// Given an exponentiation event and randomness, get assignments to the + /// exponentiation table. + pub fn assignments(exp_event: &ExpEvent) -> Vec<[F; 5]> { + let mut assignments = Vec::new(); + let base_limbs = split_u256_limb64(&exp_event.base); + let identifier = F::from(exp_event.identifier as u64); + let mut exponent = exp_event.exponent; + for (step_idx, exp_step) in exp_event.steps.iter().rev().enumerate() { + let is_last = if step_idx == exp_event.steps.len() - 1 { + F::ONE + } else { + F::ZERO + }; + let (exp_lo, exp_hi) = split_u256(&exp_step.d); + let (exponent_lo, exponent_hi) = split_u256(&exponent); + + // row 1 + assignments.push([ + identifier, + is_last, + base_limbs[0].as_u64().into(), + exponent_lo + .to_scalar() + .expect("exponent should fit to scalar"), + exp_lo + .to_scalar() + .expect("exponentiation lo should fit to scalar"), + ]); + // row 2 + assignments.push([ + identifier, + F::ZERO, + base_limbs[1].as_u64().into(), + exponent_hi + .to_scalar() + .expect("exponent hi should fit to scalar"), + exp_hi + .to_scalar() + .expect("exponentiation hi should fit to scalar"), + ]); + // row 3 + assignments.push([ + identifier, + F::ZERO, + base_limbs[2].as_u64().into(), + F::ZERO, + F::ZERO, + ]); + // row 4 + assignments.push([ + identifier, + F::ZERO, + base_limbs[3].as_u64().into(), + F::ZERO, + F::ZERO, + ]); + for _ in ROWS_PER_STEP..OFFSET_INCREMENT { + assignments.push([F::ZERO, F::ZERO, F::ZERO, F::ZERO, F::ZERO]); + } + + // update intermediate exponent. + let (exponent_div2, remainder) = exponent.div_mod(U256::from(2)); + if remainder.is_zero() { + // exponent is even + exponent = exponent_div2; + } else { + // exponent is odd + exponent = exponent - 1; + } + } + assignments + } + + /// Assign witness data from a block to the exponentiation table. + pub fn load( + &self, + layouter: &mut impl Layouter, + block: &Block, + ) -> Result<(), Error> { + layouter.assign_region( + || "exponentiation table", + |mut region| { + let mut offset = 0; + let exp_table_columns = >::advice_columns(self); + for exp_event in block.exp_events.iter() { + for row in Self::assignments::(exp_event) { + for (&column, value) in exp_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("exponentiation table row {}", offset), + column, + offset, + || Value::known(value), + )?; + } + let is_step = if offset % OFFSET_INCREMENT == 0 { + F::ONE + } else { + F::ZERO + }; + region.assign_fixed( + || format!("exponentiation table row {}", offset), + self.is_step, + offset, + || Value::known(is_step), + )?; + offset += 1; + } + } + + // pad an empty row + let row = [F::from_u128(0); 5]; + for (column, value) in exp_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("exponentiation table row {}", offset), + *column, + offset, + || Value::known(value), + )?; + } + + Ok(()) + }, + ) + } +} + +impl LookupTable for ExpTable { + fn columns(&self) -> Vec> { + vec![ + self.is_step.into(), + self.identifier.into(), + self.is_last.into(), + self.base_limb.into(), + self.exponent_lo_hi.into(), + self.exponentiation_lo_hi.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("is_step"), + String::from("identifier"), + String::from("is_last"), + String::from("base_limb"), + String::from("exponent_lo_hi"), + String::from("exponentiation_lo_hi"), + ] + } + + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + vec![ + meta.query_fixed(self.is_step, Rotation::cur()), + meta.query_advice(self.identifier, Rotation::cur()), + meta.query_advice(self.is_last, Rotation::cur()), + meta.query_advice(self.base_limb, Rotation::cur()), + meta.query_advice(self.base_limb, Rotation::next()), + meta.query_advice(self.base_limb, Rotation(2)), + meta.query_advice(self.base_limb, Rotation(3)), + meta.query_advice(self.exponent_lo_hi, Rotation::cur()), + meta.query_advice(self.exponent_lo_hi, Rotation::next()), + meta.query_advice(self.exponentiation_lo_hi, Rotation::cur()), + meta.query_advice(self.exponentiation_lo_hi, Rotation::next()), + ] + } +} diff --git a/zkevm-circuits/src/table/keccak_table.rs b/zkevm-circuits/src/table/keccak_table.rs new file mode 100644 index 0000000000..5eaff3f30d --- /dev/null +++ b/zkevm-circuits/src/table/keccak_table.rs @@ -0,0 +1,146 @@ +use super::*; + +/// Keccak Table, used to verify keccak hashing from RLC'ed input. +#[derive(Clone, Debug)] +pub struct KeccakTable { + /// True when the row is enabled + pub is_enabled: Column, + /// Byte array input as `RLC(reversed(input))` + pub input_rlc: Column, // RLC of input bytes + /// Byte array input length + pub input_len: Column, + /// RLC of the hash result + pub output_rlc: Column, // RLC of hash of input bytes +} + +impl LookupTable for KeccakTable { + fn columns(&self) -> Vec> { + vec![ + self.is_enabled.into(), + self.input_rlc.into(), + self.input_len.into(), + self.output_rlc.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("is_enabled"), + String::from("input_rlc"), + String::from("input_len"), + String::from("output_rlc"), + ] + } +} + +impl KeccakTable { + /// Construct a new KeccakTable + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + is_enabled: meta.advice_column(), + input_rlc: meta.advice_column_in(SecondPhase), + input_len: meta.advice_column(), + output_rlc: meta.advice_column_in(SecondPhase), + } + } + + /// Generate the keccak table assignments from a byte array input. + pub fn assignments( + input: &[u8], + challenges: &Challenges>, + ) -> Vec<[Value; 4]> { + let input_rlc = challenges + .keccak_input() + .map(|challenge| rlc::value(input.iter().rev(), challenge)); + let input_len = F::from(input.len() as u64); + let mut keccak = Keccak::default(); + keccak.update(input); + let output = keccak.digest(); + let output_rlc = challenges.evm_word().map(|challenge| { + rlc::value( + &Word::from_big_endian(output.as_slice()).to_le_bytes(), + challenge, + ) + }); + + vec![[ + Value::known(F::ONE), + input_rlc, + Value::known(input_len), + output_rlc, + ]] + } + + /// Assign a table row for keccak table + pub fn assign_row( + &self, + region: &mut Region, + offset: usize, + values: [Value; 4], + ) -> Result<(), Error> { + for (&column, value) in >::advice_columns(self) + .iter() + .zip(values.iter()) + { + region.assign_advice(|| format!("assign {}", offset), column, offset, || *value)?; + } + Ok(()) + } + + /// Provide this function for the case that we want to consume a keccak + /// table but without running the full keccak circuit + pub fn dev_load<'a, F: Field>( + &self, + layouter: &mut impl Layouter, + inputs: impl IntoIterator> + Clone, + challenges: &Challenges>, + ) -> Result<(), Error> { + layouter.assign_region( + || "keccak table", + |mut region| { + let mut offset = 0; + for column in >::advice_columns(self) { + region.assign_advice( + || "keccak table all-zero row", + column, + offset, + || Value::known(F::ZERO), + )?; + } + offset += 1; + + let keccak_table_columns = >::advice_columns(self); + for input in inputs.clone() { + for row in Self::assignments(input, challenges) { + // let mut column_index = 0; + for (&column, value) in keccak_table_columns.iter().zip_eq(row) { + region.assign_advice( + || format!("keccak table row {}", offset), + column, + offset, + || value, + )?; + } + offset += 1; + } + } + Ok(()) + }, + ) + } + + /// returns matchings between the circuit columns passed as parameters and + /// the table collumns + pub fn match_columns( + &self, + value_rlc: Column, + length: Column, + code_hash: Column, + ) -> Vec<(Column, Column)> { + vec![ + (value_rlc, self.input_rlc), + (length, self.input_len), + (code_hash, self.output_rlc), + ] + } +} diff --git a/zkevm-circuits/src/table/mpt_table.rs b/zkevm-circuits/src/table/mpt_table.rs new file mode 100644 index 0000000000..c62e2968a6 --- /dev/null +++ b/zkevm-circuits/src/table/mpt_table.rs @@ -0,0 +1,103 @@ +use super::*; + +/// The types of proofs in the MPT table +#[derive(Clone, Copy, Debug)] +pub enum MPTProofType { + /// Nonce updated + NonceMod = AccountFieldTag::Nonce as isize, + /// Balance updated + BalanceMod = AccountFieldTag::Balance as isize, + /// Code hash exists + CodeHashMod = AccountFieldTag::CodeHash as isize, + /// Account does not exist + NonExistingAccountProof = AccountFieldTag::NonExisting as isize, + /// Storage updated + StorageMod, + /// Storage does not exist + NonExistingStorageProof, +} +impl_expr!(MPTProofType); + +impl From for MPTProofType { + fn from(tag: AccountFieldTag) -> Self { + match tag { + AccountFieldTag::Nonce => Self::NonceMod, + AccountFieldTag::Balance => Self::BalanceMod, + AccountFieldTag::CodeHash => Self::CodeHashMod, + AccountFieldTag::NonExisting => Self::NonExistingAccountProof, + } + } +} + +/// The MptTable shared between MPT Circuit and State Circuit +#[derive(Clone, Copy, Debug)] +pub struct MptTable([Column; 7]); + +impl LookupTable for MptTable { + fn columns(&self) -> Vec> { + self.0.iter().map(|&col| col.into()).collect() + } + + fn annotations(&self) -> Vec { + vec![ + String::from("address"), + String::from("storage_key"), + String::from("proof_type"), + String::from("new_root"), + String::from("old_root"), + String::from("new_value"), + String::from("old_value"), + ] + } +} + +impl MptTable { + /// Construct a new MptTable + pub(crate) fn construct(meta: &mut ConstraintSystem) -> Self { + Self([ + meta.advice_column(), // Address + meta.advice_column_in(SecondPhase), // Storage key + meta.advice_column(), // Proof type + meta.advice_column_in(SecondPhase), // New root + meta.advice_column_in(SecondPhase), // Old root + meta.advice_column_in(SecondPhase), // New value + meta.advice_column_in(SecondPhase), // Old value + ]) + } + + pub(crate) fn assign( + &self, + region: &mut Region<'_, F>, + offset: usize, + row: &MptUpdateRow>, + ) -> Result<(), Error> { + for (column, value) in self.0.iter().zip_eq(row.values()) { + region.assign_advice(|| "assign mpt table row value", *column, offset, || *value)?; + } + Ok(()) + } + + pub(crate) fn load( + &self, + layouter: &mut impl Layouter, + updates: &MptUpdates, + randomness: Value, + ) -> Result<(), Error> { + layouter.assign_region( + || "mpt table", + |mut region| self.load_with_region(&mut region, updates, randomness), + ) + } + + pub(crate) fn load_with_region( + &self, + region: &mut Region<'_, F>, + updates: &MptUpdates, + randomness: Value, + ) -> Result<(), Error> { + for (offset, row) in updates.table_assignments(randomness).iter().enumerate() { + self.assign(region, offset, row)?; + } + Ok(()) + } +} diff --git a/zkevm-circuits/src/table/rw_table.rs b/zkevm-circuits/src/table/rw_table.rs new file mode 100644 index 0000000000..88c1febe34 --- /dev/null +++ b/zkevm-circuits/src/table/rw_table.rs @@ -0,0 +1,202 @@ +use super::*; +use bus_mapping::operation::Target; + +/// Tag to identify the operation type in a RwTable row +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIter)] +pub enum RwTableTag { + /// Start (used for padding) + Start = 1, + /// Stack operation + Stack, + /// Memory operation + Memory, + /// Account Storage operation + AccountStorage, + /// Tx Access List Account operation + TxAccessListAccount, + /// Tx Access List Account Storage operation + TxAccessListAccountStorage, + /// Tx Refund operation + TxRefund, + /// Account operation + Account, + /// Call Context operation + CallContext, + /// Tx Log operation + TxLog, + /// Tx Receipt operation + TxReceipt, +} +impl_expr!(RwTableTag); + +impl RwTableTag { + /// Returns true if the RwTable operation is reversible + pub fn is_reversible(self) -> bool { + matches!( + self, + RwTableTag::TxAccessListAccount + | RwTableTag::TxAccessListAccountStorage + | RwTableTag::TxRefund + | RwTableTag::Account + | RwTableTag::AccountStorage + ) + } +} + +impl From for RwTableTag { + fn from(t: Target) -> Self { + match t { + Target::Memory => Self::Memory, + Target::Stack => Self::Stack, + Target::Storage => Self::AccountStorage, + Target::TxAccessListAccount => Self::TxAccessListAccount, + Target::TxAccessListAccountStorage => Self::TxAccessListAccountStorage, + Target::TxRefund => Self::TxRefund, + Target::Account => Self::Account, + Target::CallContext => Self::CallContext, + Target::TxReceipt => Self::TxReceipt, + Target::TxLog => Self::TxLog, + Target::Start => Self::Start, + } + } +} + +impl From for usize { + fn from(t: RwTableTag) -> Self { + t as usize + } +} + +/// The RwTable shared between EVM Circuit and State Circuit, which contains +/// traces of the EVM state operations. +#[derive(Clone, Copy, Debug)] +pub struct RwTable { + /// Read Write Counter + pub rw_counter: Column, + /// Is Write + pub is_write: Column, + /// Tag + pub tag: Column, + /// Key1 (Id) + pub id: Column, + /// Key2 (Address) + pub address: Column, + /// Key3 (FieldTag) + pub field_tag: Column, + /// Key3 (StorageKey) + pub storage_key: Column, + /// Value + pub value: Column, + /// Value Previous + pub value_prev: Column, + /// Aux1 + pub aux1: Column, + /// Aux2 (Committed Value) + pub aux2: Column, +} + +impl LookupTable for RwTable { + fn columns(&self) -> Vec> { + vec![ + self.rw_counter.into(), + self.is_write.into(), + self.tag.into(), + self.id.into(), + self.address.into(), + self.field_tag.into(), + self.storage_key.into(), + self.value.into(), + self.value_prev.into(), + self.aux1.into(), + self.aux2.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("rw_counter"), + String::from("is_write"), + String::from("tag"), + String::from("id"), + String::from("address"), + String::from("field_tag"), + String::from("storage_key"), + String::from("value"), + String::from("value_prev"), + String::from("aux1"), + String::from("aux2"), + ] + } +} +impl RwTable { + /// Construct a new RwTable + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + rw_counter: meta.advice_column(), + is_write: meta.advice_column(), + tag: meta.advice_column(), + id: meta.advice_column(), + address: meta.advice_column(), + field_tag: meta.advice_column(), + storage_key: meta.advice_column_in(SecondPhase), + value: meta.advice_column_in(SecondPhase), + value_prev: meta.advice_column_in(SecondPhase), + // It seems that aux1 for the moment is not using randomness + // TODO check in a future review + aux1: meta.advice_column_in(SecondPhase), + aux2: meta.advice_column_in(SecondPhase), + } + } + fn assign( + &self, + region: &mut Region<'_, F>, + offset: usize, + row: &RwRow>, + ) -> Result<(), Error> { + for (column, value) in [ + (self.rw_counter, row.rw_counter), + (self.is_write, row.is_write), + (self.tag, row.tag), + (self.id, row.id), + (self.address, row.address), + (self.field_tag, row.field_tag), + (self.storage_key, row.storage_key), + (self.value, row.value), + (self.value_prev, row.value_prev), + (self.aux1, row.aux1), + (self.aux2, row.aux2), + ] { + region.assign_advice(|| "assign rw row on rw table", column, offset, || value)?; + } + Ok(()) + } + + /// Assign the `RwTable` from a `RwMap`, following the same + /// table layout that the State Circuit uses. + pub fn load( + &self, + layouter: &mut impl Layouter, + rws: &[Rw], + n_rows: usize, + challenges: Value, + ) -> Result<(), Error> { + layouter.assign_region( + || "rw table", + |mut region| self.load_with_region(&mut region, rws, n_rows, challenges), + ) + } + + pub(crate) fn load_with_region( + &self, + region: &mut Region<'_, F>, + rws: &[Rw], + n_rows: usize, + challenges: Value, + ) -> Result<(), Error> { + let (rows, _) = RwMap::table_assignments_prepad(rws, n_rows); + for (offset, row) in rows.iter().enumerate() { + self.assign(region, offset, &row.table_assignment(challenges))?; + } + Ok(()) + } +} diff --git a/zkevm-circuits/src/table/tx_table.rs b/zkevm-circuits/src/table/tx_table.rs new file mode 100644 index 0000000000..017007a614 --- /dev/null +++ b/zkevm-circuits/src/table/tx_table.rs @@ -0,0 +1,217 @@ +use super::*; + +/// Tag used to identify each field in the transaction in a row of the +/// transaction table. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum TxFieldTag { + /// Unused tag + Null = 0, + /// Nonce + Nonce, + /// Gas + Gas, + /// GasPrice + GasPrice, + /// CallerAddress + CallerAddress, + /// CalleeAddress + CalleeAddress, + /// IsCreate + IsCreate, + /// Value + Value, + /// CallDataLength + CallDataLength, + /// Gas cost for transaction call data (4 for byte == 0, 16 otherwise) + CallDataGasCost, + /// TxSignHash: Hash of the transaction without the signature, used for + /// signing. + TxSignHash, + /// CallData + CallData, +} +impl_expr!(TxFieldTag); + +/// Tag for a TxLogField in RwTable +#[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter)] +pub enum TxLogFieldTag { + /// Address field + Address = 1, + /// Topic field + Topic, + /// Data field + Data, +} +impl_expr!(TxLogFieldTag); + +/// Tag for a TxReceiptField in RwTable +#[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter, EnumCount)] +pub enum TxReceiptFieldTag { + /// Tx result + PostStateOrStatus = 1, + /// CumulativeGasUsed in the tx + CumulativeGasUsed, + /// Number of logs in the tx + LogLength, +} +impl_expr!(TxReceiptFieldTag); + +/// Alias for TxFieldTag used by EVM Circuit +pub type TxContextFieldTag = TxFieldTag; + +/// Table that contains the fields of all Transactions in a block +#[derive(Clone, Debug)] +pub struct TxTable { + /// Tx ID + pub tx_id: Column, + /// Tag (TxContextFieldTag) + pub tag: Column, + /// Index for Tag = CallData + pub index: Column, + /// Value + pub value: Column, +} + +impl TxTable { + /// Construct a new TxTable + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + tx_id: meta.advice_column(), + tag: meta.fixed_column(), + index: meta.advice_column(), + value: meta.advice_column_in(SecondPhase), + } + } + + /// Assign the `TxTable` from a list of block `Transaction`s, followig the + /// same layout that the Tx Circuit uses. + pub fn load( + &self, + layouter: &mut impl Layouter, + txs: &[Transaction], + max_txs: usize, + max_calldata: usize, + challenges: &Challenges>, + ) -> Result<(), Error> { + assert!( + txs.len() <= max_txs, + "txs.len() <= max_txs: txs.len()={}, max_txs={}", + txs.len(), + max_txs + ); + let sum_txs_calldata = txs.iter().map(|tx| tx.call_data.len()).sum(); + assert!( + sum_txs_calldata <= max_calldata, + "sum_txs_calldata <= max_calldata: sum_txs_calldata={}, max_calldata={}", + sum_txs_calldata, + max_calldata, + ); + + fn assign_row( + region: &mut Region<'_, F>, + offset: usize, + advice_columns: &[Column], + tag: &Column, + row: &[Value; 4], + msg: &str, + ) -> Result<(), Error> { + for (index, column) in advice_columns.iter().enumerate() { + region.assign_advice( + || format!("tx table {} row {}", msg, offset), + *column, + offset, + || row[if index > 0 { index + 1 } else { index }], + )?; + } + region.assign_fixed( + || format!("tx table {} row {}", msg, offset), + *tag, + offset, + || row[1], + )?; + Ok(()) + } + + layouter.assign_region( + || "tx table", + |mut region| { + let mut offset = 0; + let advice_columns = [self.tx_id, self.index, self.value]; + assign_row( + &mut region, + offset, + &advice_columns, + &self.tag, + &[(); 4].map(|_| Value::known(F::ZERO)), + "all-zero", + )?; + offset += 1; + + // Tx Table contains an initial region that has a size parametrized by max_txs + // with all the tx data except for calldata, and then a second + // region that has a size parametrized by max_calldata with all + // the tx calldata. This is required to achieve a constant fixed column tag + // regardless of the number of input txs or the calldata size of each tx. + let mut calldata_assignments: Vec<[Value; 4]> = Vec::new(); + // Assign Tx data (all tx fields except for calldata) + let padding_txs: Vec<_> = (txs.len()..max_txs) + .map(|i| Transaction { + id: i + 1, + ..Default::default() + }) + .collect(); + for tx in txs.iter().chain(padding_txs.iter()) { + let [tx_data, tx_calldata] = tx.table_assignments(*challenges); + for row in tx_data { + assign_row(&mut region, offset, &advice_columns, &self.tag, &row, "")?; + offset += 1; + } + calldata_assignments.extend(tx_calldata.iter()); + } + // Assign Tx calldata + let padding_calldata = (sum_txs_calldata..max_calldata).map(|_| { + [ + Value::known(F::ZERO), + Value::known(F::from(TxContextFieldTag::CallData as u64)), + Value::known(F::ZERO), + Value::known(F::ZERO), + ] + }); + for row in calldata_assignments.into_iter().chain(padding_calldata) { + assign_row(&mut region, offset, &advice_columns, &self.tag, &row, "")?; + offset += 1; + } + Ok(()) + }, + ) + } +} + +impl LookupTable for TxTable { + fn columns(&self) -> Vec> { + vec![ + self.tx_id.into(), + self.tag.into(), + self.index.into(), + self.value.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("tx_id"), + String::from("tag"), + String::from("index"), + String::from("value"), + ] + } + + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + vec![ + meta.query_advice(self.tx_id, Rotation::cur()), + meta.query_fixed(self.tag, Rotation::cur()), + meta.query_advice(self.index, Rotation::cur()), + meta.query_advice(self.value, Rotation::cur()), + ] + } +} From 69cb8a9329a3f5263e0ebb4ee003dd26a9470107 Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Wed, 17 May 2023 22:20:53 +0800 Subject: [PATCH 047/102] Remove RwTableTag (#1406) ### Description `RwTableTag` can be fully replaced by `Target`. ### Issue Link Part of #1391 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents We add EnumIter, Hash, Expr to Target to let it serve different needs. Note to reviewers: the `impl From for usize` is required by BinaryNumberConfig. --- bus-mapping/src/operation.rs | 29 +++++++- zkevm-circuits/src/copy_circuit.rs | 13 ++-- .../src/evm_circuit/execution/end_tx.rs | 7 +- .../evm_circuit/util/constraint_builder.rs | 44 ++++++------ zkevm-circuits/src/state_circuit.rs | 7 +- .../src/state_circuit/constraint_builder.rs | 32 ++++----- zkevm-circuits/src/state_circuit/test.rs | 4 +- zkevm-circuits/src/table.rs | 2 +- zkevm-circuits/src/table/copy_table.rs | 17 ----- zkevm-circuits/src/table/exp_table.rs | 8 --- zkevm-circuits/src/table/rw_table.rs | 67 ------------------- zkevm-circuits/src/witness/rw.rs | 59 ++++++++-------- 12 files changed, 112 insertions(+), 177 deletions(-) diff --git a/bus-mapping/src/operation.rs b/bus-mapping/src/operation.rs index cf0df09fda..8078f11957 100644 --- a/bus-mapping/src/operation.rs +++ b/bus-mapping/src/operation.rs @@ -6,6 +6,9 @@ pub(crate) mod container; pub use container::OperationContainer; pub use eth_types::evm_types::{MemoryAddress, StackAddress}; +use gadgets::impl_expr; +use halo2_proofs::plonk::Expression; +use strum_macros::EnumIter; use core::{cmp::Ordering, fmt, fmt::Debug}; use eth_types::{Address, Word}; @@ -88,10 +91,10 @@ impl RWCounter { } /// Enum used to differenciate between EVM Stack, Memory and Storage operations. -#[derive(Debug, Clone, PartialEq, Eq, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, EnumIter, Hash)] pub enum Target { /// Start is a padding operation. - Start, + Start = 1, /// Means the target of the operation is the Memory. Memory, /// Means the target of the operation is the Stack. @@ -114,6 +117,28 @@ pub enum Target { TxLog, } +impl_expr!(Target); + +impl From for usize { + fn from(value: Target) -> usize { + value.into() + } +} + +impl Target { + /// Returns true if the RwTable operation is reversible + pub fn is_reversible(self) -> bool { + matches!( + self, + Target::TxAccessListAccount + | Target::TxAccessListAccountStorage + | Target::TxRefund + | Target::Account + | Target::Storage + ) + } +} + /// Trait used for Operation Kinds. pub trait Op: Clone + Eq + Ord { diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index 0817773493..8d283abb8c 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -10,7 +10,10 @@ mod test; #[cfg(any(feature = "test", test, feature = "test-circuits"))] pub use dev::CopyCircuit as TestCopyCircuit; -use bus_mapping::circuit_input_builder::{CopyDataType, CopyEvent}; +use bus_mapping::{ + circuit_input_builder::{CopyDataType, CopyEvent}, + operation::Target, +}; use eth_types::{Field, Word}; use gadgets::{ @@ -29,8 +32,8 @@ use std::{collections::HashMap, marker::PhantomData}; use crate::{ evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, table::{ - BytecodeFieldTag, BytecodeTable, CopyTable, LookupTable, RwTable, RwTableTag, - TxContextFieldTag, TxTable, + BytecodeFieldTag, BytecodeTable, CopyTable, LookupTable, RwTable, TxContextFieldTag, + TxTable, }, util::{Challenges, SubCircuit, SubCircuitConfig}, witness, @@ -327,7 +330,7 @@ impl SubCircuitConfig for CopyCircuitConfig { vec![ meta.query_advice(rw_counter, Rotation::cur()), not::expr(meta.query_selector(q_step)), - RwTableTag::Memory.expr(), + Target::Memory.expr(), meta.query_advice(id, Rotation::cur()), // call_id meta.query_advice(addr, Rotation::cur()), // memory address 0.expr(), @@ -349,7 +352,7 @@ impl SubCircuitConfig for CopyCircuitConfig { vec![ meta.query_advice(rw_counter, Rotation::cur()), 1.expr(), - RwTableTag::TxLog.expr(), + Target::TxLog.expr(), meta.query_advice(id, Rotation::cur()), // tx_id meta.query_advice(addr, Rotation::cur()), // byte_index || field_tag || log_id 0.expr(), diff --git a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs index 9fdddd7c2b..5461f36ffc 100644 --- a/zkevm-circuits/src/evm_circuit/execution/end_tx.rs +++ b/zkevm-circuits/src/evm_circuit/execution/end_tx.rs @@ -17,11 +17,10 @@ use crate::{ }, witness::{Block, Call, ExecStep, Transaction}, }, - table::{ - BlockContextFieldTag, CallContextFieldTag, RwTableTag, TxContextFieldTag, TxReceiptFieldTag, - }, + table::{BlockContextFieldTag, CallContextFieldTag, TxContextFieldTag, TxReceiptFieldTag}, util::Expr, }; +use bus_mapping::operation::Target; use eth_types::{evm_types::MAX_REFUND_QUOTIENT_OF_GAS_USED, Field, ToScalar}; use halo2_proofs::{circuit::Value, plonk::Error}; use strum::EnumCount; @@ -284,7 +283,7 @@ impl ExecutionGadget for EndTxGadget { // first transaction needs TxReceiptFieldTag::COUNT(3) lookups to tx receipt, // while later transactions need 4 (with one extra cumulative gas read) lookups let rw = &block.rws[( - RwTableTag::TxReceipt, + Target::TxReceipt, (tx.id - 2) * (TxReceiptFieldTag::COUNT + 1) + 2, )]; rw.receipt_value() diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index a9f0523e0c..93ea3d51ca 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -6,12 +6,12 @@ use crate::{ util::{Cell, RandomLinearCombination, Word}, }, table::{ - AccountFieldTag, BytecodeFieldTag, CallContextFieldTag, RwTableTag, TxContextFieldTag, - TxLogFieldTag, TxReceiptFieldTag, + AccountFieldTag, BytecodeFieldTag, CallContextFieldTag, TxContextFieldTag, TxLogFieldTag, + TxReceiptFieldTag, }, util::{build_tx_log_expression, Challenges, Expr}, }; -use bus_mapping::state_db::EMPTY_CODE_HASH_LE; +use bus_mapping::{operation::Target, state_db::EMPTY_CODE_HASH_LE}; use eth_types::Field; use gadgets::util::not; use halo2_proofs::{ @@ -677,7 +677,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { name: &str, counter: Expression, is_write: Expression, - tag: RwTableTag, + tag: Target, values: RwValues, ) { let name = format!("rw lookup {}", name); @@ -698,7 +698,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { &mut self, name: &'static str, is_write: Expression, - tag: RwTableTag, + tag: Target, values: RwValues, ) { self.rw_lookup_with_counter( @@ -726,7 +726,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { fn reversible_write( &mut self, name: &'static str, - tag: RwTableTag, + tag: Target, values: RwValues, reversion_info: Option<&mut ReversionInfo>, ) { @@ -769,7 +769,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { ) { self.reversible_write( "TxAccessListAccount write", - RwTableTag::TxAccessListAccount, + Target::TxAccessListAccount, RwValues::new( tx_id, account_address, @@ -793,7 +793,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.rw_lookup( "account access list read", false.expr(), - RwTableTag::TxAccessListAccount, + Target::TxAccessListAccount, RwValues::new( tx_id, account_address, @@ -818,7 +818,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { ) { self.reversible_write( "TxAccessListAccountStorage write", - RwTableTag::TxAccessListAccountStorage, + Target::TxAccessListAccountStorage, RwValues::new( tx_id, account_address, @@ -843,7 +843,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.rw_lookup( "TxAccessListAccountStorage read", false.expr(), - RwTableTag::TxAccessListAccountStorage, + Target::TxAccessListAccountStorage, RwValues::new( tx_id, account_address, @@ -863,7 +863,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.rw_lookup( "TxRefund read", false.expr(), - RwTableTag::TxRefund, + Target::TxRefund, RwValues::new( tx_id, 0.expr(), @@ -886,7 +886,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { ) { self.reversible_write( "TxRefund write", - RwTableTag::TxRefund, + Target::TxRefund, RwValues::new( tx_id, 0.expr(), @@ -912,7 +912,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.rw_lookup( "Account read", false.expr(), - RwTableTag::Account, + Target::Account, RwValues::new( 0.expr(), account_address, @@ -936,7 +936,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { ) { self.reversible_write( "Account write", - RwTableTag::Account, + Target::Account, RwValues::new( 0.expr(), account_address, @@ -964,7 +964,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.rw_lookup( "account_storage_read", false.expr(), - RwTableTag::AccountStorage, + Target::Storage, RwValues::new( tx_id, account_address, @@ -991,7 +991,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { ) { self.reversible_write( "AccountStorage write", - RwTableTag::AccountStorage, + Target::Storage, RwValues::new( tx_id, account_address, @@ -1042,7 +1042,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.rw_lookup( "CallContext lookup", is_write, - RwTableTag::CallContext, + Target::CallContext, RwValues::new( call_id.unwrap_or_else(|| self.curr.state.call_id.expr()), 0.expr(), @@ -1117,7 +1117,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.rw_lookup( "Stack lookup", is_write, - RwTableTag::Stack, + Target::Stack, RwValues::new( self.curr.state.call_id.expr(), self.curr.state.stack_pointer.expr() + stack_pointer_offset, @@ -1143,7 +1143,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.rw_lookup( "Memory lookup", is_write, - RwTableTag::Memory, + Target::Memory, RwValues::new( call_id.unwrap_or_else(|| self.curr.state.call_id.expr()), memory_address, @@ -1168,7 +1168,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.rw_lookup( "log data lookup", 1.expr(), - RwTableTag::TxLog, + Target::TxLog, RwValues::new( tx_id, build_tx_log_expression(index, field_tag.expr(), log_id), @@ -1194,7 +1194,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { self.rw_lookup( "tx receipt lookup", is_write, - RwTableTag::TxReceipt, + Target::TxReceipt, RwValues::new( tx_id, 0.expr(), @@ -1215,7 +1215,7 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> { "Start lookup", counter, 0.expr(), - RwTableTag::Start, + Target::Start, RwValues { id: 0.expr(), address: 0.expr(), diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index e07415e288..224822114b 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -10,6 +10,7 @@ mod random_linear_combination; mod dev; #[cfg(any(feature = "test", test))] mod test; +use bus_mapping::operation::Target; #[cfg(any(feature = "test", test, feature = "test-circuits"))] pub use dev::StateCircuit as TestStateCircuit; @@ -19,7 +20,7 @@ use self::{ }; use crate::{ evm_circuit::{param::N_BYTES_WORD, util::rlc}, - table::{AccountFieldTag, LookupTable, MPTProofType, MptTable, RwTable, RwTableTag}, + table::{AccountFieldTag, LookupTable, MPTProofType, MptTable, RwTable}, util::{Challenges, Expr, SubCircuit, SubCircuitConfig}, witness::{self, MptUpdates, Rw, RwMap}, }; @@ -275,7 +276,7 @@ impl StateCircuitConfig { assert_eq!(state_root, old_root); state_root = new_root; } - if matches!(row.tag(), RwTableTag::CallContext) && !row.is_write() { + if matches!(row.tag(), Target::CallContext) && !row.is_write() { assert_eq!(row.value_assignment(randomness), F::ZERO, "{:?}", row); } state_root @@ -393,7 +394,7 @@ impl StateCircuitConfig { /// Keys for sorting the rows of the state circuit #[derive(Clone, Copy)] pub struct SortKeysConfig { - tag: BinaryNumberConfig, + tag: BinaryNumberConfig, id: MpiConfig, address: MpiConfig, field_tag: Column, diff --git a/zkevm-circuits/src/state_circuit/constraint_builder.rs b/zkevm-circuits/src/state_circuit/constraint_builder.rs index 58706b5d82..4c73e0b542 100644 --- a/zkevm-circuits/src/state_circuit/constraint_builder.rs +++ b/zkevm-circuits/src/state_circuit/constraint_builder.rs @@ -7,9 +7,10 @@ use crate::{ param::N_BYTES_WORD, util::{math_gadget::generate_lagrange_base_polynomial, not}, }, - table::{AccountFieldTag, MPTProofType, RwTableTag}, + table::{AccountFieldTag, MPTProofType}, util::Expr, }; +use bus_mapping::operation::Target; use eth_types::Field; use gadgets::binary_number::BinaryNumberConfig; use halo2_proofs::plonk::Expression; @@ -101,35 +102,34 @@ impl ConstraintBuilder { pub fn build(&mut self, q: &Queries) { self.build_general_constraints(q); - self.condition(q.tag_matches(RwTableTag::Start), |cb| { + self.condition(q.tag_matches(Target::Start), |cb| { cb.build_start_constraints(q) }); - self.condition(q.tag_matches(RwTableTag::Memory), |cb| { + self.condition(q.tag_matches(Target::Memory), |cb| { cb.build_memory_constraints(q) }); - self.condition(q.tag_matches(RwTableTag::Stack), |cb| { + self.condition(q.tag_matches(Target::Stack), |cb| { cb.build_stack_constraints(q) }); - self.condition(q.tag_matches(RwTableTag::AccountStorage), |cb| { + self.condition(q.tag_matches(Target::Storage), |cb| { cb.build_account_storage_constraints(q) }); - self.condition(q.tag_matches(RwTableTag::TxAccessListAccount), |cb| { + self.condition(q.tag_matches(Target::TxAccessListAccount), |cb| { cb.build_tx_access_list_account_constraints(q) }); - self.condition( - q.tag_matches(RwTableTag::TxAccessListAccountStorage), - |cb| cb.build_tx_access_list_account_storage_constraints(q), - ); - self.condition(q.tag_matches(RwTableTag::TxRefund), |cb| { + self.condition(q.tag_matches(Target::TxAccessListAccountStorage), |cb| { + cb.build_tx_access_list_account_storage_constraints(q) + }); + self.condition(q.tag_matches(Target::TxRefund), |cb| { cb.build_tx_refund_constraints(q) }); - self.condition(q.tag_matches(RwTableTag::Account), |cb| { + self.condition(q.tag_matches(Target::Account), |cb| { cb.build_account_constraints(q) }); - self.condition(q.tag_matches(RwTableTag::CallContext), |cb| { + self.condition(q.tag_matches(Target::CallContext), |cb| { cb.build_call_context_constraints(q) }); - self.condition(q.tag_matches(RwTableTag::TxLog), |cb| { + self.condition(q.tag_matches(Target::TxLog), |cb| { cb.build_tx_log_constraints(q) }); } @@ -617,8 +617,8 @@ impl Queries { self.mpt_proof_type.clone() } - fn tag_matches(&self, tag: RwTableTag) -> Expression { - BinaryNumberConfig::::value_equals_expr(tag, self.tag_bits.clone()) + fn tag_matches(&self, tag: Target) -> Expression { + BinaryNumberConfig::::value_equals_expr(tag, self.tag_bits.clone()) } fn first_access(&self) -> Expression { diff --git a/zkevm-circuits/src/state_circuit/test.rs b/zkevm-circuits/src/state_circuit/test.rs index bd3c1afd9f..8656bab364 100644 --- a/zkevm-circuits/src/state_circuit/test.rs +++ b/zkevm-circuits/src/state_circuit/test.rs @@ -1,7 +1,7 @@ #![allow(unused_imports)] pub use super::{dev::*, *}; use crate::{ - table::{AccountFieldTag, CallContextFieldTag, RwTableTag, TxLogFieldTag, TxReceiptFieldTag}, + table::{AccountFieldTag, CallContextFieldTag, TxLogFieldTag, TxReceiptFieldTag}, util::{unusable_rows, SubCircuit}, witness::{MptUpdates, Rw, RwMap}, }; @@ -824,7 +824,7 @@ fn invalid_stack_address_change() { #[test] fn invalid_tags() { let first_row_offset = -isize::try_from(N_ROWS).unwrap(); - let tags: BTreeSet = RwTableTag::iter().map(|x| x as usize).collect(); + let tags: BTreeSet = Target::iter().map(|x| x as usize).collect(); for i in 0..16 { if tags.contains(&i) { continue; diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 538b894c5b..c9ba47c01a 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -50,7 +50,7 @@ pub(crate) use exp_table::ExpTable; pub(crate) use keccak_table::KeccakTable; pub(crate) use mpt_table::{MPTProofType, MptTable}; -pub(crate) use rw_table::{RwTable, RwTableTag}; +pub(crate) use rw_table::RwTable; pub(crate) use tx_table::{ TxContextFieldTag, TxFieldTag, TxLogFieldTag, TxReceiptFieldTag, TxTable, }; diff --git a/zkevm-circuits/src/table/copy_table.rs b/zkevm-circuits/src/table/copy_table.rs index 86ad806df9..9db69d7c27 100644 --- a/zkevm-circuits/src/table/copy_table.rs +++ b/zkevm-circuits/src/table/copy_table.rs @@ -1,22 +1,5 @@ use super::*; -// use crate::{ -// table::LookupTable, -// witness::Block, -// }; -// use bus_mapping::circuit_input_builder::ExpEvent; -// use eth_types::{Field, ToScalar, U256}; -// use halo2_proofs::{ -// circuit::{Layouter, Region, Value}, -// plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, -// poly::Rotation, -// }; -// use itertools::Itertools; -// use gadgets::{ -// binary_number::{BinaryNumberChip, BinaryNumberConfig}, -// util::{split_u256, split_u256_limb64}, -// }; - type CopyTableRow = [(Value, &'static str); 8]; type CopyCircuitRow = [(Value, &'static str); 4]; diff --git a/zkevm-circuits/src/table/exp_table.rs b/zkevm-circuits/src/table/exp_table.rs index f47dca99a3..c2ee645e53 100644 --- a/zkevm-circuits/src/table/exp_table.rs +++ b/zkevm-circuits/src/table/exp_table.rs @@ -6,14 +6,6 @@ use crate::{ witness::Block, }; use bus_mapping::circuit_input_builder::ExpEvent; -// use eth_types::{Field, ToScalar, U256}; -// use gadgets::util::{split_u256, split_u256_limb64}; -// use halo2_proofs::{ -// circuit::{Layouter, Region, Value}, -// plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, -// poly::Rotation, -// }; -// use itertools::Itertools; /// Lookup table within the Exponentiation circuit. #[derive(Clone, Copy, Debug)] diff --git a/zkevm-circuits/src/table/rw_table.rs b/zkevm-circuits/src/table/rw_table.rs index 88c1febe34..ca56b1f89b 100644 --- a/zkevm-circuits/src/table/rw_table.rs +++ b/zkevm-circuits/src/table/rw_table.rs @@ -1,71 +1,4 @@ use super::*; -use bus_mapping::operation::Target; - -/// Tag to identify the operation type in a RwTable row -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumIter)] -pub enum RwTableTag { - /// Start (used for padding) - Start = 1, - /// Stack operation - Stack, - /// Memory operation - Memory, - /// Account Storage operation - AccountStorage, - /// Tx Access List Account operation - TxAccessListAccount, - /// Tx Access List Account Storage operation - TxAccessListAccountStorage, - /// Tx Refund operation - TxRefund, - /// Account operation - Account, - /// Call Context operation - CallContext, - /// Tx Log operation - TxLog, - /// Tx Receipt operation - TxReceipt, -} -impl_expr!(RwTableTag); - -impl RwTableTag { - /// Returns true if the RwTable operation is reversible - pub fn is_reversible(self) -> bool { - matches!( - self, - RwTableTag::TxAccessListAccount - | RwTableTag::TxAccessListAccountStorage - | RwTableTag::TxRefund - | RwTableTag::Account - | RwTableTag::AccountStorage - ) - } -} - -impl From for RwTableTag { - fn from(t: Target) -> Self { - match t { - Target::Memory => Self::Memory, - Target::Stack => Self::Stack, - Target::Storage => Self::AccountStorage, - Target::TxAccessListAccount => Self::TxAccessListAccount, - Target::TxAccessListAccountStorage => Self::TxAccessListAccountStorage, - Target::TxRefund => Self::TxRefund, - Target::Account => Self::Account, - Target::CallContext => Self::CallContext, - Target::TxReceipt => Self::TxReceipt, - Target::TxLog => Self::TxLog, - Target::Start => Self::Start, - } - } -} - -impl From for usize { - fn from(t: RwTableTag) -> Self { - t as usize - } -} /// The RwTable shared between EVM Circuit and State Circuit, which contains /// traces of the EVM state operations. diff --git a/zkevm-circuits/src/witness/rw.rs b/zkevm-circuits/src/witness/rw.rs index 074166005a..a01bf1e7ea 100644 --- a/zkevm-circuits/src/witness/rw.rs +++ b/zkevm-circuits/src/witness/rw.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use bus_mapping::{ exec_trace::OperationRef, - operation::{self, AccountField, CallContextField, TxLogField, TxReceiptField}, + operation::{self, AccountField, CallContextField, Target, TxLogField, TxReceiptField}, }; use eth_types::{Address, Field, ToAddress, ToLittleEndian, ToScalar, Word, U256}; use halo2_proofs::{circuit::Value, halo2curves::bn256::Fr}; @@ -11,7 +11,7 @@ use itertools::Itertools; use crate::{ evm_circuit::util::rlc, - table::{AccountFieldTag, CallContextFieldTag, RwTableTag, TxLogFieldTag, TxReceiptFieldTag}, + table::{AccountFieldTag, CallContextFieldTag, TxLogFieldTag, TxReceiptFieldTag}, util::build_tx_log_address, }; @@ -19,12 +19,12 @@ use super::MptUpdates; /// Rw constainer for a witness block #[derive(Debug, Default, Clone)] -pub struct RwMap(pub HashMap>); +pub struct RwMap(pub HashMap>); -impl std::ops::Index<(RwTableTag, usize)> for RwMap { +impl std::ops::Index<(Target, usize)> for RwMap { type Output = Rw; - fn index(&self, (tag, idx): (RwTableTag, usize)) -> &Self::Output { + fn index(&self, (tag, idx): (Target, usize)) -> &Self::Output { &self.0.get(&tag).unwrap()[idx] } } @@ -33,7 +33,6 @@ impl std::ops::Index for RwMap { type Output = Rw; fn index(&self, OperationRef(tag, idx): OperationRef) -> &Self::Output { - let tag: RwTableTag = tag.into(); &self.0.get(&tag).unwrap()[idx] } } @@ -44,7 +43,7 @@ impl RwMap { for (idx, rw_counter) in self .0 .iter() - .filter(|(tag, _rs)| !matches!(tag, RwTableTag::Start)) + .filter(|(tag, _rs)| !matches!(tag, Target::Start)) .flat_map(|(_tag, rs)| rs) .map(|r| r.rw_counter()) .sorted() @@ -477,19 +476,19 @@ impl Rw { } } - pub(crate) fn tag(&self) -> RwTableTag { + pub(crate) fn tag(&self) -> Target { match self { - Self::Start { .. } => RwTableTag::Start, - Self::Memory { .. } => RwTableTag::Memory, - Self::Stack { .. } => RwTableTag::Stack, - Self::AccountStorage { .. } => RwTableTag::AccountStorage, - Self::TxAccessListAccount { .. } => RwTableTag::TxAccessListAccount, - Self::TxAccessListAccountStorage { .. } => RwTableTag::TxAccessListAccountStorage, - Self::TxRefund { .. } => RwTableTag::TxRefund, - Self::Account { .. } => RwTableTag::Account, - Self::CallContext { .. } => RwTableTag::CallContext, - Self::TxLog { .. } => RwTableTag::TxLog, - Self::TxReceipt { .. } => RwTableTag::TxReceipt, + Self::Start { .. } => Target::Start, + Self::Memory { .. } => Target::Memory, + Self::Stack { .. } => Target::Stack, + Self::AccountStorage { .. } => Target::Storage, + Self::TxAccessListAccount { .. } => Target::TxAccessListAccount, + Self::TxAccessListAccountStorage { .. } => Target::TxAccessListAccountStorage, + Self::TxRefund { .. } => Target::TxRefund, + Self::Account { .. } => Target::Account, + Self::CallContext { .. } => Target::CallContext, + Self::TxLog { .. } => Target::TxLog, + Self::TxReceipt { .. } => Target::TxReceipt, } } @@ -661,7 +660,7 @@ impl From<&operation::OperationContainer> for RwMap { let mut rws = HashMap::default(); rws.insert( - RwTableTag::Start, + Target::Start, container .start .iter() @@ -671,7 +670,7 @@ impl From<&operation::OperationContainer> for RwMap { .collect(), ); rws.insert( - RwTableTag::TxAccessListAccount, + Target::TxAccessListAccount, container .tx_access_list_account .iter() @@ -686,7 +685,7 @@ impl From<&operation::OperationContainer> for RwMap { .collect(), ); rws.insert( - RwTableTag::TxAccessListAccountStorage, + Target::TxAccessListAccountStorage, container .tx_access_list_account_storage .iter() @@ -702,7 +701,7 @@ impl From<&operation::OperationContainer> for RwMap { .collect(), ); rws.insert( - RwTableTag::TxRefund, + Target::TxRefund, container .tx_refund .iter() @@ -716,7 +715,7 @@ impl From<&operation::OperationContainer> for RwMap { .collect(), ); rws.insert( - RwTableTag::Account, + Target::Account, container .account .iter() @@ -735,7 +734,7 @@ impl From<&operation::OperationContainer> for RwMap { .collect(), ); rws.insert( - RwTableTag::AccountStorage, + Target::Storage, container .storage .iter() @@ -752,7 +751,7 @@ impl From<&operation::OperationContainer> for RwMap { .collect(), ); rws.insert( - RwTableTag::CallContext, + Target::CallContext, container .call_context .iter() @@ -800,7 +799,7 @@ impl From<&operation::OperationContainer> for RwMap { .collect(), ); rws.insert( - RwTableTag::Stack, + Target::Stack, container .stack .iter() @@ -814,7 +813,7 @@ impl From<&operation::OperationContainer> for RwMap { .collect(), ); rws.insert( - RwTableTag::Memory, + Target::Memory, container .memory .iter() @@ -830,7 +829,7 @@ impl From<&operation::OperationContainer> for RwMap { .collect(), ); rws.insert( - RwTableTag::TxLog, + Target::TxLog, container .tx_log .iter() @@ -850,7 +849,7 @@ impl From<&operation::OperationContainer> for RwMap { .collect(), ); rws.insert( - RwTableTag::TxReceipt, + Target::TxReceipt, container .tx_receipt .iter() From 70d7da497405918ab66f337c566bcb57e6d98a03 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Fri, 19 May 2023 15:24:31 +0200 Subject: [PATCH 048/102] Fix infinite loop (#1421) ### Description Fix an infinite loop from a `From` implementation calling itself. ### Issue Link Resolve https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1420 Related https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1417 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) ### Contents @ChihChengLiang found that this issue was introduced in https://github.com/privacy-scaling-explorations/zkevm-circuits/pull/1406 and by debugging on the debug build I found the infinite loop (which caused the stack to overflow which terminated the program with a segfault). The segfault is not observed in the release build, I guess the compiler optimizes the recursive call into an infinite loop, so the stack is never exhausted. --- bus-mapping/src/operation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bus-mapping/src/operation.rs b/bus-mapping/src/operation.rs index 8078f11957..0de8e6cff3 100644 --- a/bus-mapping/src/operation.rs +++ b/bus-mapping/src/operation.rs @@ -121,7 +121,7 @@ impl_expr!(Target); impl From for usize { fn from(value: Target) -> usize { - value.into() + value as usize } } From 244fe706d5622495e30404d229ef472313f739ff Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Sat, 20 May 2023 00:21:06 +0800 Subject: [PATCH 049/102] updates --- .../src/circuit_tools/cell_manager.rs | 44 ++++++++++------- .../src/circuit_tools/tests/util.rs | 48 ++++++++++++------- zkevm-circuits/src/mpt_circuit.rs | 2 +- 3 files changed, 57 insertions(+), 37 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index 149708c8eb..5b7f8889b1 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -122,6 +122,12 @@ pub(crate) enum CellType_ { Lookup(T), } +impl Default for CellType_ { + fn default() -> Self { + CellType_::StoragePhase1 + } +} + pub trait TableType: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash {} #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] @@ -202,24 +208,24 @@ pub struct CellManager { #[derive(Clone, Debug)] pub struct PhaseConfig { + phase1: usize, + phase2: usize, phase3: Vec<(T, usize)>, //lookup - phase2: usize, // rlc - phase1: usize, // byte } impl PhaseConfig { pub fn new( - tables: Vec<&dyn LookupTable>, + phase1: usize, phase2: usize, - phase1: usize + tables: Vec<&dyn LookupTable> ) -> Self { let phase3 = tables.iter().map(|t| (t.get_type(), t.columns().len()) ).collect::>(); Self { - phase3, - phase2, phase1, + phase2, + phase3, } } } @@ -268,15 +274,13 @@ impl CellManager { let mut column_idx = 0; - // Mark columns used for lookups in Phase3 - for (table, count) in &phase_config.phase3 { - for _ in 0usize..*count { - assert_eq!(advices[column_idx].column_type().phase(), 2u8); - columns[column_idx].cell_type = CellType_::Lookup(*table); - column_idx += 1; - } - } + // Mark columns used for byte lookup + for _ in 0..phase_config.phase1 { + assert_eq!(advices[column_idx].column_type().phase(), 0); + column_idx += 1; + } + // Mark columns used for Phase2 constraints for _ in 0..phase_config.phase2 { assert_eq!(advices[column_idx].column_type().phase(), 1u8); @@ -284,12 +288,16 @@ impl CellManager { column_idx += 1; } - // Mark columns used for byte lookup - for _ in 0..phase_config.phase1 { - assert_eq!(advices[column_idx].column_type().phase(), 0); - column_idx += 1; + // Mark columns used for lookups in Phase3 + for (table, count) in &phase_config.phase3 { + for _ in 0usize..*count { + assert_eq!(advices[column_idx].column_type().phase(), 2u8); + columns[column_idx].cell_type = CellType_::Lookup(*table); + column_idx += 1; + } } + // Mark columns used for copy constraints for _ in 0..copy_columns { meta.enable_equality(advices[column_idx]); diff --git a/zkevm-circuits/src/circuit_tools/tests/util.rs b/zkevm-circuits/src/circuit_tools/tests/util.rs index 75f06a85a5..bae74245bb 100644 --- a/zkevm-circuits/src/circuit_tools/tests/util.rs +++ b/zkevm-circuits/src/circuit_tools/tests/util.rs @@ -13,7 +13,7 @@ use gadgets::util::Scalar; use halo2_proofs::circuit::{SimpleFloorPlanner, layouter, Layouter, Region}; use halo2_proofs::dev::MockProver; use halo2_proofs::halo2curves::bn256::Fr; -use halo2_proofs::plonk::{Any, Circuit, FirstPhase, Challenge, SecondPhase, ThirdPhase, Fixed}; +use halo2_proofs::plonk::{Any, Circuit, FirstPhase, Challenge, SecondPhase, ThirdPhase, Fixed, Selector}; use halo2_proofs::{ circuit::{AssignedCell, Value}, plonk::{ConstraintSystem, Advice, Column, Error, Expression, VirtualCells}, @@ -30,7 +30,7 @@ use halo2_proofs::{ const MAX_DEG: usize = 5; const CM_HEIGHT: usize = 10; -const COPY_COL_NUM: usize = 10; +const COPY_COL_NUM: usize = 1; const REGION_HEIGHT: usize = 10; #[derive(Clone)] @@ -53,6 +53,7 @@ impl LookupTable for TestTable { #[derive(Clone)] pub struct TestConfig { + pub(crate) sel: Selector, pub(crate) q_enable: Column, pub(crate) q_count: Column, pub(crate) cell_columns: Vec>, @@ -69,41 +70,48 @@ impl TestConfig { ) -> Self { // Get columns + let sel = meta.selector(); let q_enable = meta.fixed_column(); let q_count = meta.advice_column(); let cell_columns = (0..10) .map(|i| match i { - 0..=2 => meta.advice_column_in(ThirdPhase), + 0..=2 => meta.advice_column_in(FirstPhase), 3..=5 => meta.advice_column_in(SecondPhase), - 6..=9 => meta.advice_column_in(FirstPhase), + 6..=9 => meta.advice_column_in(ThirdPhase), + 10 => meta.advice_column_in(FirstPhase), // Copy _ => unreachable!(), } ).collect::>(); // Init cell manager and constraint builder - let phase_config: PhaseConfig = PhaseConfig::new::(vec![&table], 2, 3); + let phase_config: PhaseConfig = PhaseConfig::new::(3, 3, vec![&table]); let mut cm = CellManager::new(meta, CM_HEIGHT,&cell_columns,0,phase_config,COPY_COL_NUM ); - let mut cb = ConstraintBuilder::new(MAX_DEG, Some(cm)); - + let mut cb: ConstraintBuilder = ConstraintBuilder::new(MAX_DEG, Some(cm)); + let mut cell_gadget = CellGadget::default(); meta.create_gate("Test Gate", |meta| { // Config row counts circuit!([meta, cb], { + // All configuration of inner gadgets must be wrapped in ifx! + // it pushes a condition into cb, which is gonna be multiplied with the upcoming constraints. + // then if you turn off q_enable, your inner gadgets will be disabled. + // otherwise you'll see missing selector error. ifx!(f!(q_enable) => { require!(a!(q_count, 1) => a!(q_count) + 1.expr()); + // Init Gadgets + cell_gadget = CellGadget::configure( + &mut cb, + // Convert Challenge into Expression + meta.query_challenge(r1), + ); }) }); - // Init Gadgets - cell_gadget = CellGadget::configure( - &mut cb, - // Convert Challenge into Expression - meta.query_challenge(r1), - ); cb.generate_constraints() }); Self { + sel, q_enable, q_count, cell_columns, @@ -121,10 +129,14 @@ impl TestConfig { || "cell gadget", |mut region| { - for offset in 0..50 { + self.sel.enable(&mut region, 0); + + for offset in 0..20 { assignf!(region, (self.q_enable, offset) => 1.scalar())?; assign!(region, (self.q_count, offset) => offset.scalar())?; } + assign!(region, (self.q_count, 20) => 20.scalar())?; + // Value of challenge is obtained from layouter. // We query it once during synthesis and // make it accessable across Config through CachedRegion. @@ -144,7 +156,7 @@ impl TestConfig { layouter.assign_region( || "fixed table", |mut region| { - for offset in 0..50 { + for offset in 0..10 { // Don't need CachedRegion here since we don't cache intermediate values. assignf!(region, (self.table.a, offset) => offset.scalar())?; assignf!(region, (self.table.b, offset) => (offset + 1).scalar())?; @@ -235,7 +247,7 @@ impl Circuit for TestCircuit { a: meta.fixed_column(), b: meta.fixed_column(), }; - let _dummy_phase1 = meta.advice_column(); + let _dummy_phase1 = meta.advice_column_in(FirstPhase); let r1 = meta.challenge_usable_after(FirstPhase); let config = TestConfig::new(meta, table, r1); @@ -248,7 +260,7 @@ impl Circuit for TestCircuit { mut layouter: impl halo2_proofs::circuit::Layouter ) -> Result<(), Error> { let r1 = layouter.get_challenge(r1); - config.load_fixed_table(&mut layouter); + config.load_fixed_table(&mut layouter)?; config.assign(&mut layouter, r1) } } @@ -256,7 +268,7 @@ impl Circuit for TestCircuit { #[test] fn test() { let circuit = TestCircuit::::default(); - let prover = MockProver::::run(5, &circuit, vec![]).unwrap(); + let prover = MockProver::::run(6, &circuit, vec![]).unwrap(); prover.assert_satisfied_par(); } \ No newline at end of file diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index d58c07cde2..98744a5aae 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -214,7 +214,7 @@ impl MPTConfig { memory: memory.clone(), }; - let _phase_config = PhaseConfig::new::(vec![&keccak_table], 2, 2); + let _phase_config = PhaseConfig::new::(2, 2, vec![&keccak_table]); let mut cb = MPTConstraintBuilder::new(33 + 10, None); meta.create_gate("MPT", |meta| { From 43c67c91ca566fd2b7f3588979c537006090f185 Mon Sep 17 00:00:00 2001 From: Steven Date: Sat, 20 May 2023 15:10:49 +0800 Subject: [PATCH 050/102] Bug: fix to truncate offset from Word to Uint64 when length is zero for some opcodes (#1415) ### Description Reference go-ethereum function [calcMemSize64WithUint](https://github.com/ethereum/go-ethereum/blob/84c3799e21d61d677965715fe09f8209660b4009/core/vm/common.go#L38), ignore to check Uint64 overflow for memory offset if length is zero. it is also called by [calcMemSize64](https://github.com/ethereum/go-ethereum/blob/84c3799e21d61d677965715fe09f8209660b4009/core/vm/common.go#LL31C9-L31C30). And both are used for opcodes in [memory_table.go](https://github.com/ethereum/go-ethereum/blob/84c3799e21d61d677965715fe09f8209660b4009/core/vm/memory_table.go#L20) as `memorySize` in [jump_table.go](https://github.com/ethereum/go-ethereum/blob/84c3799e21d61d677965715fe09f8209660b4009/core/vm/jump_table.go#L387). For Call opcodes, in offset and size are truncated to Uint64 as [opCall](https://github.com/ethereum/go-ethereum/blob/84c3799e21d61d677965715fe09f8209660b4009/core/vm/instructions.go#LL672C60-L672C60). ### Issue Link Related issue https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1301 Original local PR https://github.com/scroll-tech/zkevm-circuits/pull/393 ### Type of change - [X] Bug fix (non-breaking change which fixes an issue) ### How Has This Been Tested? 1. Fix `testool` case `randomStatetest85_d0_g0_v0`. 2. Add test cases of overflow offset and zero length for related opcodes. --- bus-mapping/src/circuit_input_builder.rs | 15 +++-- bus-mapping/src/evm/opcodes/calldatacopy.rs | 4 +- bus-mapping/src/evm/opcodes/callop.rs | 6 +- bus-mapping/src/evm/opcodes/codecopy.rs | 4 +- bus-mapping/src/evm/opcodes/create.rs | 4 +- bus-mapping/src/evm/opcodes/extcodecopy.rs | 4 +- bus-mapping/src/evm/opcodes/return_revert.rs | 4 +- bus-mapping/src/evm/opcodes/returndatacopy.rs | 4 +- bus-mapping/src/evm/opcodes/sha3.rs | 11 +++- .../src/evm_circuit/execution/calldatacopy.rs | 30 ++++++---- .../src/evm_circuit/execution/callop.rs | 47 ++++++++++------ .../src/evm_circuit/execution/codecopy.rs | 19 ++++--- .../src/evm_circuit/execution/extcodecopy.rs | 56 ++++++++++++++----- .../evm_circuit/execution/return_revert.rs | 19 +++++-- .../evm_circuit/execution/returndatacopy.rs | 23 +++++--- .../src/evm_circuit/execution/sha3.rs | 15 +++++ 16 files changed, 187 insertions(+), 78 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 057458d073..11e676d561 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -366,10 +366,17 @@ pub fn get_create_init_code<'a>( call_ctx: &'a CallContext, step: &GethExecStep, ) -> Result<&'a [u8], Error> { - let offset = step.stack.nth_last(1)?; - let length = step.stack.nth_last(2)?; - Ok(&call_ctx.memory.0 - [offset.low_u64() as usize..(offset.low_u64() + length.low_u64()) as usize]) + let offset = step.stack.nth_last(1)?.low_u64() as usize; + let length = step.stack.nth_last(2)?.as_usize(); + + let mem_len = call_ctx.memory.0.len(); + if offset >= mem_len { + return Ok(&[]); + } + + let offset_end = offset.checked_add(length).unwrap_or(mem_len); + + Ok(&call_ctx.memory.0[offset..offset_end]) } /// Retrieve the memory offset and length of call. diff --git a/bus-mapping/src/evm/opcodes/calldatacopy.rs b/bus-mapping/src/evm/opcodes/calldatacopy.rs index 238b17c993..eb724c7e5e 100644 --- a/bus-mapping/src/evm/opcodes/calldatacopy.rs +++ b/bus-mapping/src/evm/opcodes/calldatacopy.rs @@ -105,7 +105,9 @@ fn gen_copy_event( let call_data_offset = state.call()?.call_data_offset; let call_data_length = state.call()?.call_data_length; - let dst_addr = memory_offset.as_u64(); + // Get low Uint64 of memory offset to generate copy steps. Since memory + // offset could be Uint64 overflow if memory length is zero. + let dst_addr = memory_offset.low_u64(); let src_addr_end = call_data_offset.checked_add(call_data_length).unwrap(); // Reset start offset to end offset if overflow. diff --git a/bus-mapping/src/evm/opcodes/callop.rs b/bus-mapping/src/evm/opcodes/callop.rs index 1786bf2f7b..b4fbdef3ec 100644 --- a/bus-mapping/src/evm/opcodes/callop.rs +++ b/bus-mapping/src/evm/opcodes/callop.rs @@ -31,9 +31,11 @@ impl Opcode for CallOpcode { let geth_step = &geth_steps[0]; let mut exec_step = state.new_step(geth_step)?; - let args_offset = geth_step.stack.nth_last(N_ARGS - 4)?.as_usize(); + // In offset and length are truncated to Uint64 for call opcodes as: + // + let args_offset = geth_step.stack.nth_last(N_ARGS - 4)?.low_u64() as usize; let args_length = geth_step.stack.nth_last(N_ARGS - 3)?.as_usize(); - let ret_offset = geth_step.stack.nth_last(N_ARGS - 2)?.as_usize(); + let ret_offset = geth_step.stack.nth_last(N_ARGS - 2)?.low_u64() as usize; let ret_length = geth_step.stack.nth_last(N_ARGS - 1)?.as_usize(); // we need to keep the memory until parse_call complete diff --git a/bus-mapping/src/evm/opcodes/codecopy.rs b/bus-mapping/src/evm/opcodes/codecopy.rs index 578f1c733f..372c8d22af 100644 --- a/bus-mapping/src/evm/opcodes/codecopy.rs +++ b/bus-mapping/src/evm/opcodes/codecopy.rs @@ -78,7 +78,9 @@ fn gen_copy_event( let bytecode: Bytecode = state.code(code_hash)?.into(); let code_size = bytecode.code.len() as u64; - let dst_addr = dst_offset.as_u64(); + // Get low Uint64 of offset to generate copy steps. Since offset could be + // Uint64 overflow if length is zero. + let dst_addr = dst_offset.low_u64(); let src_addr_end = code_size; // Reset start offset to end offset if overflow. diff --git a/bus-mapping/src/evm/opcodes/create.rs b/bus-mapping/src/evm/opcodes/create.rs index d40fa678d3..2f6d40d409 100644 --- a/bus-mapping/src/evm/opcodes/create.rs +++ b/bus-mapping/src/evm/opcodes/create.rs @@ -18,7 +18,9 @@ impl Opcode for DummyCreate { // TODO: replace dummy create here let geth_step = &geth_steps[0]; - let offset = geth_step.stack.nth_last(1)?.as_usize(); + // Get low Uint64 of offset to generate copy steps. Since offset could + // be Uint64 overflow if length is zero. + let offset = geth_step.stack.nth_last(1)?.low_u64() as usize; let length = geth_step.stack.nth_last(2)?.as_usize(); let curr_memory_word_size = (state.call_ctx()?.memory.len() as u64) / 32; diff --git a/bus-mapping/src/evm/opcodes/extcodecopy.rs b/bus-mapping/src/evm/opcodes/extcodecopy.rs index 8160bc9455..bd0dc455de 100644 --- a/bus-mapping/src/evm/opcodes/extcodecopy.rs +++ b/bus-mapping/src/evm/opcodes/extcodecopy.rs @@ -137,7 +137,9 @@ fn gen_copy_event( }; let code_size = bytecode.code.len() as u64; - let dst_addr = dst_offset.as_u64(); + // Get low Uint64 of offset to generate copy steps. Since offset could be + // Uint64 overflow if length is zero. + let dst_addr = dst_offset.low_u64(); let src_addr_end = code_size; // Reset start offset to end offset if overflow. diff --git a/bus-mapping/src/evm/opcodes/return_revert.rs b/bus-mapping/src/evm/opcodes/return_revert.rs index d3bd76fd2b..d81d63b021 100644 --- a/bus-mapping/src/evm/opcodes/return_revert.rs +++ b/bus-mapping/src/evm/opcodes/return_revert.rs @@ -40,7 +40,9 @@ impl Opcode for ReturnRevert { call.is_success.to_word(), ); - let offset = offset.as_usize(); + // Get low Uint64 of offset to generate copy steps. Since offset could + // be Uint64 overflow if length is zero. + let offset = offset.low_u64() as usize; let length = length.as_usize(); // Case A in the spec. diff --git a/bus-mapping/src/evm/opcodes/returndatacopy.rs b/bus-mapping/src/evm/opcodes/returndatacopy.rs index f1a14a4b16..a7830523d5 100644 --- a/bus-mapping/src/evm/opcodes/returndatacopy.rs +++ b/bus-mapping/src/evm/opcodes/returndatacopy.rs @@ -123,7 +123,9 @@ fn gen_copy_event( state: &mut CircuitInputStateRef, geth_step: &GethExecStep, ) -> Result { - let dst_addr = geth_step.stack.nth_last(0)?.as_u64(); + // Get low Uint64 of destination offset to generate copy steps. Since it + // could be Uint64 overflow if length is zero. + let dst_addr = geth_step.stack.nth_last(0)?.low_u64(); let data_offset = geth_step.stack.nth_last(1)?.as_u64(); let length = geth_step.stack.nth_last(2)?.as_u64(); diff --git a/bus-mapping/src/evm/opcodes/sha3.rs b/bus-mapping/src/evm/opcodes/sha3.rs index 65f4408817..ca2cc1a430 100644 --- a/bus-mapping/src/evm/opcodes/sha3.rs +++ b/bus-mapping/src/evm/opcodes/sha3.rs @@ -40,7 +40,9 @@ impl Opcode for Sha3 { let memory = state .call_ctx()? .memory - .read_chunk(offset.as_usize().into(), size.as_usize().into()); + // Get low Uint64 of offset to generate copy steps. Since offset + // could be Uint64 overflow if length is zero. + .read_chunk(offset.low_u64().into(), size.as_usize().into()); // keccak-256 hash of the given data in memory. let sha3 = keccak256(&memory); @@ -65,8 +67,11 @@ impl Opcode for Sha3 { state.push_copy( &mut exec_step, CopyEvent { - src_addr: offset.as_u64(), - src_addr_end: offset.as_u64() + size.as_u64(), + src_addr: offset.low_u64(), + src_addr_end: offset + .low_u64() + .checked_add(size.as_u64()) + .unwrap_or(u64::MAX), src_type: CopyDataType::Memory, src_id: NumberOrHash::Number(call_id), dst_addr: 0, diff --git a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs index 219941902b..6d1fb475cc 100644 --- a/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs @@ -263,9 +263,9 @@ mod test { fn test_root_ok( call_data_length: usize, - memory_offset: usize, length: usize, data_offset: Word, + memory_offset: Word, ) { let bytecode = bytecode! { PUSH32(length) @@ -302,9 +302,9 @@ mod test { fn test_internal_ok( call_data_offset: usize, call_data_length: usize, - dst_offset: usize, length: usize, data_offset: Word, + dst_offset: Word, ) { let (addr_a, addr_b) = (mock::MOCK_ACCOUNTS[0], mock::MOCK_ACCOUNTS[1]); @@ -343,31 +343,37 @@ mod test { #[test] fn calldatacopy_gadget_simple() { - test_root_ok(0x40, 0x40, 10, 0x00.into()); - test_internal_ok(0x40, 0x40, 0xA0, 10, 0x10.into()); + test_root_ok(0x40, 10, 0x00.into(), 0x40.into()); + test_internal_ok(0x40, 0x40, 10, 0x10.into(), 0xA0.into()); } #[test] fn calldatacopy_gadget_large() { - test_root_ok(0x204, 0x103, 0x101, 0x102.into()); - test_internal_ok(0x30, 0x204, 0x103, 0x101, 0x102.into()); + test_root_ok(0x204, 0x101, 0x102.into(), 0x103.into()); + test_internal_ok(0x30, 0x204, 0x101, 0x102.into(), 0x103.into()); } #[test] fn calldatacopy_gadget_out_of_bound() { - test_root_ok(0x40, 0x40, 40, 0x20.into()); - test_internal_ok(0x40, 0x20, 0xA0, 10, 0x28.into()); + test_root_ok(0x40, 40, 0x20.into(), 0x40.into()); + test_internal_ok(0x40, 0x20, 10, 0x28.into(), 0xA0.into()); } #[test] fn calldatacopy_gadget_zero_length() { - test_root_ok(0x40, 0x40, 0, 0x00.into()); - test_internal_ok(0x40, 0x40, 0xA0, 0, 0x10.into()); + test_root_ok(0x40, 0, 0x00.into(), 0x40.into()); + test_internal_ok(0x40, 0x40, 0, 0x10.into(), 0xA0.into()); } #[test] fn calldatacopy_gadget_data_offset_overflow() { - test_root_ok(0x40, 0x40, 0, Word::MAX); - test_internal_ok(0x40, 0x40, 0xA0, 0, Word::MAX); + test_root_ok(0x40, 10, Word::MAX, 0x40.into()); + test_internal_ok(0x40, 0x40, 10, Word::MAX, 0xA0.into()); + } + + #[test] + fn calldatacopy_gadget_overflow_memory_offset_and_zero_length() { + test_root_ok(0x40, 0, 0x40.into(), Word::MAX); + test_internal_ok(0x40, 0x40, 0, 0x10.into(), Word::MAX); } } diff --git a/zkevm-circuits/src/evm_circuit/execution/callop.rs b/zkevm-circuits/src/evm_circuit/execution/callop.rs index 7aae484769..f5a78bf06a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/callop.rs +++ b/zkevm-circuits/src/evm_circuit/execution/callop.rs @@ -691,31 +691,31 @@ mod test { }, // With memory expansion Stack { - cd_offset: 64, + cd_offset: 64.into(), cd_length: 320, - rd_offset: 0, + rd_offset: Word::zero(), rd_length: 32, ..Default::default() }, Stack { - cd_offset: 0, + cd_offset: Word::zero(), cd_length: 32, - rd_offset: 64, + rd_offset: 64.into(), rd_length: 320, ..Default::default() }, Stack { - cd_offset: 0xFFFFFF, + cd_offset: 0xFFFFFF.into(), cd_length: 0, - rd_offset: 0xFFFFFF, + rd_offset: 0xFFFFFF.into(), rd_length: 0, ..Default::default() }, // With memory expansion and value Stack { - cd_offset: 64, + cd_offset: 64.into(), cd_length: 320, - rd_offset: 0, + rd_offset: 0.into(), rd_length: 32, value: Word::from(10).pow(18.into()), ..Default::default() @@ -732,13 +732,28 @@ mod test { } } + #[test] + fn callop_overflow_offset_and_zero_length() { + let stack = Stack { + cd_offset: Word::MAX, + cd_length: 0, + rd_offset: Word::MAX, + rd_length: 0, + ..Default::default() + }; + + TEST_CALL_OPCODES + .iter() + .for_each(|opcode| test_ok(caller(opcode, stack, true), callee(bytecode! {}))); + } + #[derive(Clone, Copy, Debug, Default)] struct Stack { gas: u64, value: Word, - cd_offset: u64, + cd_offset: Word, cd_length: u64, - rd_offset: u64, + rd_offset: Word, rd_length: u64, } @@ -765,9 +780,9 @@ mod test { // Call twice for testing both cold and warm access let mut bytecode = bytecode! { PUSH32(Word::from(stack.rd_length)) - PUSH32(Word::from(stack.rd_offset)) + PUSH32(stack.rd_offset) PUSH32(Word::from(stack.cd_length)) - PUSH32(Word::from(stack.cd_offset)) + PUSH32(stack.cd_offset) }; if is_call_or_callcode { bytecode.push(32, stack.value); @@ -777,9 +792,9 @@ mod test { PUSH32(Word::from(stack.gas)) .write_op(*opcode) PUSH32(Word::from(stack.rd_length)) - PUSH32(Word::from(stack.rd_offset)) + PUSH32(stack.rd_offset) PUSH32(Word::from(stack.cd_length)) - PUSH32(Word::from(stack.cd_offset)) + PUSH32(stack.cd_offset) }); if is_call_or_callcode { bytecode.push(32, stack.value); @@ -807,9 +822,9 @@ mod test { let mut bytecode = bytecode! { PUSH32(Word::from(stack.rd_length)) - PUSH32(Word::from(stack.rd_offset)) + PUSH32(stack.rd_offset) PUSH32(Word::from(stack.cd_length)) - PUSH32(Word::from(stack.cd_offset)) + PUSH32(stack.cd_offset) }; if is_call_or_callcode { bytecode.push(32, stack.value); diff --git a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs index 020a88fedf..f47fef2936 100644 --- a/zkevm-circuits/src/evm_circuit/execution/codecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/codecopy.rs @@ -200,7 +200,7 @@ mod tests { use eth_types::{bytecode, Word}; use mock::TestContext; - fn test_ok(code_offset: Word, memory_offset: usize, size: usize, large: bool) { + fn test_ok(code_offset: Word, memory_offset: Word, size: usize, large: bool) { let mut code = bytecode! {}; if large { for _ in 0..size { @@ -210,7 +210,7 @@ mod tests { let tail = bytecode! { PUSH32(Word::from(size)) PUSH32(code_offset) - PUSH32(Word::from(memory_offset)) + PUSH32(memory_offset) CODECOPY STOP }; @@ -224,18 +224,23 @@ mod tests { #[test] fn codecopy_gadget_simple() { - test_ok(0x00.into(), 0x00, 0x20, false); - test_ok(0x30.into(), 0x20, 0x30, false); - test_ok(0x20.into(), 0x10, 0x42, false); + test_ok(0x00.into(), 0x00.into(), 0x20, false); + test_ok(0x30.into(), 0x20.into(), 0x30, false); + test_ok(0x20.into(), 0x10.into(), 0x42, false); } #[test] fn codecopy_gadget_large() { - test_ok(0x102.into(), 0x103, 0x101, true); + test_ok(0x102.into(), 0x103.into(), 0x101, true); } #[test] fn codecopy_gadget_code_offset_overflow() { - test_ok(Word::MAX, 0x103, 0x101, true); + test_ok(Word::MAX, 0x103.into(), 0x101, true); + } + + #[test] + fn codecopy_gadget_overflow_memory_offset_and_zero_size() { + test_ok(0x102.into(), Word::MAX, 0, false); } } diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index fcecb36866..ad0d793837 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -252,7 +252,7 @@ mod test { fn test_ok( external_account: Option, code_offset: Word, - memory_offset: usize, + memory_offset: Word, length: usize, is_warm: bool, ) { @@ -309,8 +309,8 @@ mod test { #[test] fn extcodecopy_empty_account() { - test_ok(None, 0x00.into(), 0x00, 0x36, true); // warm account - test_ok(None, 0x00.into(), 0x00, 0x36, false); // cold account + test_ok(None, Word::zero(), Word::zero(), 0x36, true); // warm account + test_ok(None, Word::zero(), Word::zero(), 0x36, false); // cold account } #[test] @@ -321,8 +321,8 @@ mod test { code: Bytes::from([10, 40]), ..Default::default() }), - 0x00.into(), - 0x00, + Word::zero(), + Word::zero(), 0x36, true, ); // warm account @@ -333,8 +333,8 @@ mod test { code: Bytes::from([10, 40]), ..Default::default() }), - 0x00.into(), - 0x00, + Word::zero(), + Word::zero(), 0x36, false, ); // cold account @@ -348,8 +348,8 @@ mod test { code: Bytes::from(rand_bytes_array::<256>()), ..Default::default() }), - 0x00.into(), - 0x00, + Word::zero(), + Word::zero(), 0x36, true, ); @@ -359,8 +359,8 @@ mod test { code: Bytes::from(rand_bytes_array::<256>()), ..Default::default() }), - 0x00.into(), - 0x00, + Word::zero(), + Word::zero(), 0x36, false, ); @@ -375,7 +375,7 @@ mod test { ..Default::default() }), 0x20.into(), - 0x00, + Word::zero(), 0x104, true, ); @@ -386,7 +386,7 @@ mod test { ..Default::default() }), 0x20.into(), - 0x00, + Word::zero(), 0x104, false, ); @@ -401,7 +401,7 @@ mod test { ..Default::default() }), Word::MAX, - 0x00, + Word::zero(), 0x36, true, ); @@ -412,9 +412,35 @@ mod test { ..Default::default() }), Word::MAX, - 0x00, + Word::zero(), 0x36, false, ); } + + #[test] + fn extcodecopy_overflow_memory_offset_and_zero_length() { + test_ok( + Some(Account { + address: *EXTERNAL_ADDRESS, + code: Bytes::from(rand_bytes_array::<256>()), + ..Default::default() + }), + 0x20.into(), + Word::MAX, + 0, + true, + ); + test_ok( + Some(Account { + address: *EXTERNAL_ADDRESS, + code: Bytes::from(rand_bytes_array::<256>()), + ..Default::default() + }), + 0x20.into(), + Word::MAX, + 0, + true, + ); + } } diff --git a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs index e584a2d8d5..cad355c2bc 100644 --- a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs +++ b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs @@ -355,16 +355,16 @@ mod test { const CALLEE_ADDRESS: Address = Address::repeat_byte(0xff); const CALLER_ADDRESS: Address = Address::repeat_byte(0x34); - fn callee_bytecode(is_return: bool, offset: u64, length: u64) -> Bytecode { - let memory_bytes = [0x60; 10]; + fn callee_bytecode(is_return: bool, offset: u128, length: u64) -> Bytecode { + let memory_bytes = [0x60; 6]; let memory_address = 0; let memory_value = Word::from_big_endian(&memory_bytes); let mut code = bytecode! { - PUSH10(memory_value) + PUSH6(memory_value) PUSH1(memory_address) MSTORE PUSH2(length) - PUSH2(32u64 - u64::try_from(memory_bytes.len()).unwrap() + offset) + PUSH17(Word::from(offset) + 32 - memory_bytes.len()) }; code.write_op(if is_return { OpcodeId::RETURN @@ -651,4 +651,15 @@ mod test { let text_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(); CircuitTestBuilder::new_from_test_ctx(text_ctx).run(); } + + #[test] + fn test_return_overflow_offset_and_zero_length() { + for is_return in [true, false] { + let code = callee_bytecode(is_return, u128::MAX, 0); + CircuitTestBuilder::new_from_test_ctx( + TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(), + ) + .run(); + } + } } diff --git a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs index 4a16767f58..aed699e68a 100644 --- a/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs @@ -275,9 +275,9 @@ mod test { fn test_ok_internal( return_data_offset: usize, return_data_size: usize, - dest_offset: usize, - offset: usize, size: usize, + offset: usize, + dest_offset: Word, ) { let (addr_a, addr_b) = (mock::MOCK_ACCOUNTS[0], mock::MOCK_ACCOUNTS[1]); @@ -330,38 +330,43 @@ mod test { #[test] fn returndatacopy_gadget_do_nothing() { - test_ok_internal(0x00, 0x02, 0x10, 0x00, 0x00); + test_ok_internal(0, 2, 0, 0, 0x10.into()); } #[test] fn returndatacopy_gadget_simple() { - test_ok_internal(0x00, 0x02, 0x10, 0x00, 0x02); + test_ok_internal(0, 2, 2, 0, 0x10.into()); } #[test] fn returndatacopy_gadget_large() { - test_ok_internal(0x00, 0x20, 0x20, 0x00, 0x20); + test_ok_internal(0, 0x20, 0x20, 0, 0x20.into()); } #[test] fn returndatacopy_gadget_large_partial() { - test_ok_internal(0x00, 0x20, 0x20, 0x10, 0x10); + test_ok_internal(0, 0x20, 0x10, 0x10, 0x20.into()); } #[test] fn returndatacopy_gadget_zero_length() { - test_ok_internal(0x00, 0x00, 0x20, 0x00, 0x00); + test_ok_internal(0, 0, 0, 0, 0x20.into()); } #[test] fn returndatacopy_gadget_long_length() { // rlc value matters only if length > 255, i.e., size.cells.len() > 1 - test_ok_internal(0x00, 0x200, 0x20, 0x00, 0x150); + test_ok_internal(0, 0x200, 0x150, 0, 0x20.into()); } #[test] fn returndatacopy_gadget_big_offset() { // rlc value matters only if length > 255, i.e., size.cells.len() > 1 - test_ok_internal(0x200, 0x200, 0x200, 0x00, 0x150); + test_ok_internal(0x200, 0x200, 0x150, 0, 0x200.into()); + } + + #[test] + fn returndatacopy_gadget_overflow_offset_and_zero_length() { + test_ok_internal(0, 0x20, 0, 0x20, Word::MAX); } } diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index 6d948f1880..736b961dfa 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -158,6 +158,7 @@ impl ExecutionGadget for Sha3Gadget { mod tests { use crate::test_util::CircuitTestBuilder; use bus_mapping::{circuit_input_builder::CircuitsParams, evm::Sha3CodeGen}; + use eth_types::{bytecode, U256}; use mock::TestContext; fn test_ok(mut gen: Sha3CodeGen) { @@ -192,4 +193,18 @@ mod tests { test_ok(Sha3CodeGen::mem_eq_size(0x303, 0x404)); test_ok(Sha3CodeGen::mem_gt_size(0x404, 0x505)); } + + #[test] + fn sha3_gadget_overflow_offset_and_zero_size() { + let bytecode = bytecode! { + PUSH1(0) + PUSH32(U256::MAX) + SHA3 + }; + + CircuitTestBuilder::new_from_test_ctx( + TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(), + ) + .run(); + } } From bcfd2d5faa9ab87a9a35e98a03a6aa1e9b52a2e2 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Sat, 20 May 2023 17:26:30 +0800 Subject: [PATCH 051/102] refactor CellManager --- .../src/circuit_tools/cell_manager.rs | 214 ++++++++++++++++-- zkevm-circuits/src/circuit_tools/table.rs | 72 +++++- .../src/circuit_tools/tests/util.rs | 15 ++ 3 files changed, 281 insertions(+), 20 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index 5b7f8889b1..706a033129 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -3,17 +3,20 @@ use crate::util::{Expr, query_expression}; use crate::circuit_tools::{table::LookupTable, cached_region::{CachedRegion, ChallengeSet}}; use eth_types::Field; +use halo2_proofs::plonk::{Any, SecondPhase, ThirdPhase, FirstPhase}; use halo2_proofs::{ circuit::{AssignedCell, Value}, plonk::{ConstraintSystem, Advice, Column, Error, Expression, VirtualCells}, poly::Rotation, }; use halo2_proofs::arithmetic::FieldExt; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use std::fmt::Debug; use std::hash::Hash; use strum_macros::EnumIter; +use super::table::LookupTable_; + #[derive(Clone, Debug, Default)] pub(crate) struct Cell { // expression for constraint @@ -104,14 +107,51 @@ impl Expr for &Cell { } } -// #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -// pub(crate) enum CellType { -// StoragePhase1, -// StoragePhase2, -// StoragePermutation, -// LookupByte, -// Lookup(Table), -// } +#[derive(Clone, Debug)] +pub struct CellConfig { + cell_type: C, + num_columns: usize, + phase: u8, + is_permute: bool, +} + +impl CellConfig { + pub fn init_columns(&self, meta: &mut ConstraintSystem) -> Vec>{ + let mut columns = Vec::with_capacity(self.num_columns); + match self.phase { + 0 => { + columns.iter_mut() + .map(|c| *c = meta.advice_column_in(FirstPhase)); + }, + 1 => { + columns.iter_mut() + .map(|c| *c = meta.advice_column_in(SecondPhase)); + }, + 2 => { + columns.iter_mut() + .map(|c| *c = meta.advice_column_in(ThirdPhase)); + }, + _ => unreachable!(), + }; + if self.is_permute { + columns.iter().map(|c| meta.enable_equality(c.clone())); + } + columns + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) enum CellType { + StoragePhase1, + StoragePhase2, + StoragePermutation, + LookupByte, + Lookup(T), +} + +pub trait CellTypeTrait: + Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash {} + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) enum CellType_ { @@ -184,12 +224,158 @@ pub(crate) struct CellColumn { expr: Expression, } +#[derive(Clone, Debug)] +pub(crate) struct CellColumn_ { + index: usize, + cell_type: C, + height: usize, + expr: Expression, +} + impl Expr for CellColumn { fn expr(&self) -> Expression { self.expr.clone() } } +#[derive(Clone, Debug)] +pub struct CellManager_ { + max_height: usize, + total_width: usize, + cells: HashMap>)>, + cell_configs: Vec>, + columns: Vec>, +} + +impl CellManager_ { + + // 一步到位 + pub(crate) fn new>( + meta: &mut ConstraintSystem, + mut cell_configs: Vec>, + tables: Vec<&dyn LookupTable_>, + offset: usize, + max_height: usize, + ) -> Self { + + let mut cells = HashMap::new(); + let mut cell_columns = Vec::new(); + let mut total_width = 0; + + // User need to put fixed columns after advice if have any + // permutation is not enable by default + for table in tables { + if !table.advice_columns().is_empty() { + cell_configs.push(CellConfig { + cell_type: table.get_type_().into(), + num_columns: table.advice_columns().len(), + phase: table.phase(), + is_permute: false, + }); + } + if !table.fixed_columns().is_empty() { + cell_configs.push(CellConfig { + cell_type: table.get_type_().into(), + num_columns: table.fixed_columns().len(), + phase: table.phase(), + is_permute: false, + }); + } + }; + + cell_configs + .iter() + .map(|c| { + let cols = c.init_columns(meta); + let mut cell_list = Vec::with_capacity(cols.len() * max_height); + let start_width = total_width; + query_expression(meta, |meta| { + for w in 0..cols.len() { + for h in 0..max_height { + let cell: Cell<_> = Cell::new(meta, cols[w], offset + h, total_width); + cell_list.push(cell); + } + cell_columns.push(CellColumn_ { + index: w, + cell_type: c.cell_type, + height: 0, + expr: cell_list[cols.len()-1].expr().clone(), + }); + total_width += 1; + } + }); + cells.insert(c.cell_type, (start_width, cell_list)); + }); + + Self { + max_height, + total_width, + cells, + cell_configs, + columns: cell_columns, + } + } + + pub(crate) fn get_width(&self) -> usize { + self.total_width + } + + pub(crate) fn get_max_height(&self) -> usize { + self.max_height + } + + pub(crate) fn set_max_height(&mut self, max_height: usize) { + self.max_height = max_height; + } + + pub(crate) fn get_used_height(&self) -> usize { + self.columns + .iter() + .map(|column| column.height) + .max() + .unwrap() + } + + pub(crate) fn get_config(&self, cell_type: C) -> &CellConfig { + self.cell_configs + .iter() + .find(|c| c.cell_type == cell_type) + .expect("Cell type not found") + } + + pub(crate) fn get_typed_columns(&self, cell_type: C) -> Vec> { + let (start_width, _) = self.cells.get(&cell_type).expect("Cell type not found"); + let window = self.get_config(cell_type).num_columns; + self.columns[*start_width..window].to_owned() + } + + pub(crate) fn query_cells(&mut self, cell_type: C, count: usize) -> Vec> { + let mut targets = Vec::with_capacity(count); + let (start_width, cell_list) = self.cells.get(&cell_type).expect("Cell type not found"); + let window = self.get_config(cell_type).num_columns; + + while targets.len() < count { + // Iterate the window of columns designated for this CellType + // No need to find the best height because cells should be return in order + self.columns[*start_width..start_width + window] + .iter_mut() + .enumerate() + .map(|(i, c)| { + assert!(c.cell_type == cell_type); + if c.height < self.max_height { + targets.push(cell_list[i + c.height].clone()); + c.height += 1; + } + }); + } + targets + } + + pub(crate) fn query_cell(&mut self, cell_type: C) -> Cell { + self.query_cells(cell_type, 1)[0].clone() + } +} + #[derive(Clone, Debug)] pub struct CellManager { // Thoughts (Cecilia): Integrate CellManager's function into Halo2's VirtualCell @@ -232,15 +418,6 @@ impl PhaseConfig { impl CellManager { - // 一步到位 - pub(crate) fn new_( - _meta: &mut ConstraintSystem, - _max_height: usize, - _max_width: usize, - _phase_config: PhaseConfig, - ) -> Self { - todo!() - } pub(crate) fn new( meta: &mut ConstraintSystem, // meta只出现一次,new的时候把所有cover的cells都query一遍 @@ -297,7 +474,6 @@ impl CellManager { } } - // Mark columns used for copy constraints for _ in 0..copy_columns { meta.enable_equality(advices[column_idx]); diff --git a/zkevm-circuits/src/circuit_tools/table.rs b/zkevm-circuits/src/circuit_tools/table.rs index d72644663c..e08ba30341 100644 --- a/zkevm-circuits/src/circuit_tools/table.rs +++ b/zkevm-circuits/src/circuit_tools/table.rs @@ -11,7 +11,6 @@ use super::{cell_manager::{TableType, SingleTable}}; /// Trait used to define lookup tables pub trait LookupTable { - fn get_type(&self) -> T; /// Returns the list of ALL the table columns following the table order. @@ -27,6 +26,16 @@ pub trait LookupTable { .collect() } + /// Returns the list of ALL the table fixed columns following the table + /// order. + fn fixed_columns(&self) -> Vec> { + self.columns() + .iter() + .map(|&col| col.try_into()) + .filter_map(|res| res.ok()) + .collect() + } + /// Returns the String annotations associated to each column of the table. fn annotations(&self) -> Vec; @@ -78,3 +87,64 @@ impl> + Copy, const W: usize> LookupTable { + type TableType_; + + fn get_type_(&self) -> Self::TableType_; + + fn phase(&self) -> u8; + + /// Returns the list of ALL the table columns following the table order. + fn columns(&self) -> Vec>; + + /// Returns the list of ALL the table advice columns following the table + /// order. + fn advice_columns(&self) -> Vec> { + self.columns() + .iter() + .map(|&col| col.try_into()) + .filter_map(|res| res.ok()) + .collect() + } + + /// Returns the list of ALL the table fixed columns following the table + /// order. + fn fixed_columns(&self) -> Vec> { + self.columns() + .iter() + .map(|&col| col.try_into()) + .filter_map(|res| res.ok()) + .collect() + } + + /// Returns the String annotations associated to each column of the table. + fn annotations(&self) -> Vec; + + /// Return the list of expressions used to define the lookup table. + fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { + self.columns() + .iter() + .map(|&column| meta.query_any(column, Rotation::cur())) + .collect() + } + + /// Annotates a lookup table by passing annotations for each of it's + /// columns. + fn annotate_columns(&self, cs: &mut ConstraintSystem) { + self.columns() + .iter() + .zip(self.annotations().iter()) + .for_each(|(&col, ann)| cs.annotate_lookup_any_column(col, || ann)) + } + + /// Annotates columns of a table embedded within a circuit region. + fn annotate_columns_in_region(&self, region: &mut Region) { + self.columns() + .iter() + .zip(self.annotations().iter()) + .for_each(|(&col, ann)| region.name_column(|| ann, col)) + } +} + diff --git a/zkevm-circuits/src/circuit_tools/tests/util.rs b/zkevm-circuits/src/circuit_tools/tests/util.rs index bae74245bb..3367a35d2e 100644 --- a/zkevm-circuits/src/circuit_tools/tests/util.rs +++ b/zkevm-circuits/src/circuit_tools/tests/util.rs @@ -271,4 +271,19 @@ fn test() { let prover = MockProver::::run(6, &circuit, vec![]).unwrap(); prover.assert_satisfied_par(); + use plotters::prelude::*; + let root = BitMapBackend::new("test.png", (1024, 768)).into_drawing_area(); + root.fill(&WHITE).unwrap(); + let root = root + .titled("Test Layout", ("sans-serif", 60)) + .unwrap(); + + halo2_proofs::dev::CircuitLayout::default() + // Render the circuit onto your area! + // The first argument is the size parameter for the circuit. + .show_cell_annotations(true) + .region_by_name("cell gadget") + .render(6, &circuit.clone(), &root) + .unwrap(); + } \ No newline at end of file From 2c5f3c54f583965cf6efa6d43a8b5baeea3afec6 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Sat, 20 May 2023 17:45:41 +0800 Subject: [PATCH 052/102] moved things around --- .../src/circuit_tools/cell_manager.rs | 193 +++++++++--------- 1 file changed, 95 insertions(+), 98 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index 706a033129..858fe32453 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -119,18 +119,15 @@ impl CellConfig { pub fn init_columns(&self, meta: &mut ConstraintSystem) -> Vec>{ let mut columns = Vec::with_capacity(self.num_columns); match self.phase { - 0 => { - columns.iter_mut() - .map(|c| *c = meta.advice_column_in(FirstPhase)); - }, - 1 => { - columns.iter_mut() - .map(|c| *c = meta.advice_column_in(SecondPhase)); - }, - 2 => { - columns.iter_mut() - .map(|c| *c = meta.advice_column_in(ThirdPhase)); - }, + 0 => columns.iter_mut() + .map(|c| *c = meta.advice_column_in(FirstPhase)) + .collect::>(), + 1 => columns.iter_mut() + .map(|c| *c = meta.advice_column_in(SecondPhase)) + .collect::>(), + 2 => columns.iter_mut() + .map(|c| *c = meta.advice_column_in(ThirdPhase)) + .collect::>(), _ => unreachable!(), }; if self.is_permute { @@ -140,90 +137,11 @@ impl CellConfig { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) enum CellType { - StoragePhase1, - StoragePhase2, - StoragePermutation, - LookupByte, - Lookup(T), -} pub trait CellTypeTrait: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash {} -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) enum CellType_ { - StoragePhase1, - StoragePhase2, - StoragePermutation, - LookupByte, - Lookup(T), -} - -impl Default for CellType_ { - fn default() -> Self { - CellType_::StoragePhase1 - } -} - -pub trait TableType: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash {} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] -pub enum SingleTable { - Default, -} -impl TableType for SingleTable {} -/// Example - -// use super::table::{TestTableType, MptTable, BytecodeTable}; - -// fn work_like_this(meta: &mut ConstraintSystem) { -// let config: PhaseConfig = PhaseConfig::new( -// &[MptTable::construct(meta), BytecodeTable::construct(meta)], -// 2, -// 3 -// ); -// } - - -impl CellType_ { - // The phase that given `Expression` becomes evaluateable. - fn expr_phase(expr: &Expression) -> u8 { - use Expression::*; - match expr { - Challenge(challenge) => challenge.phase() + 1, - Advice(query) => query.phase(), - Constant(_) | Selector(_) | Fixed(_) | Instance(_) => 0, - Negated(a) | Expression::Scaled(a, _) => Self::expr_phase(a), - Sum(a, b) | Product(a, b) => std::cmp::max(Self::expr_phase(a), Self::expr_phase(b)), - } - } - - /// Return the storage phase of phase - pub(crate) fn storage_for_phase(phase: u8) -> CellType_ { - match phase { - 0 => CellType_::StoragePhase1, - 1 => CellType_::StoragePhase2, - _ => unreachable!(), - } - } - - /// Return the storage cell of the expression - pub(crate) fn storage_for_expr(expr: &Expression) -> CellType_ { - Self::storage_for_phase::(Self::expr_phase::(expr)) - } -} - -#[derive(Clone, Debug)] -pub(crate) struct CellColumn { - index: usize, - cell_type: CellType_, - height: usize, - expr: Expression, -} - #[derive(Clone, Debug)] pub(crate) struct CellColumn_ { index: usize, @@ -232,11 +150,6 @@ pub(crate) struct CellColumn_ { expr: Expression, } -impl Expr for CellColumn { - fn expr(&self) -> Expression { - self.expr.clone() - } -} #[derive(Clone, Debug)] pub struct CellManager_ { @@ -305,7 +218,7 @@ impl CellManager_ { } }); cells.insert(c.cell_type, (start_width, cell_list)); - }); + }).collect::>(); Self { max_height, @@ -366,7 +279,7 @@ impl CellManager_ { targets.push(cell_list[i + c.height].clone()); c.height += 1; } - }); + }).collect::>(); } targets } @@ -376,6 +289,90 @@ impl CellManager_ { } } + + +// ============================== Old Version ================================= + + + + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) enum CellType_ { + StoragePhase1, + StoragePhase2, + StoragePermutation, + LookupByte, + Lookup(T), +} + +impl Default for CellType_ { + fn default() -> Self { + CellType_::StoragePhase1 + } +} + +pub trait TableType: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash {} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] +pub enum SingleTable { + Default, +} +impl TableType for SingleTable {} +/// Example + +// use super::table::{TestTableType, MptTable, BytecodeTable}; + +// fn work_like_this(meta: &mut ConstraintSystem) { +// let config: PhaseConfig = PhaseConfig::new( +// &[MptTable::construct(meta), BytecodeTable::construct(meta)], +// 2, +// 3 +// ); +// } + + +impl CellType_ { + // The phase that given `Expression` becomes evaluateable. + fn expr_phase(expr: &Expression) -> u8 { + use Expression::*; + match expr { + Challenge(challenge) => challenge.phase() + 1, + Advice(query) => query.phase(), + Constant(_) | Selector(_) | Fixed(_) | Instance(_) => 0, + Negated(a) | Expression::Scaled(a, _) => Self::expr_phase(a), + Sum(a, b) | Product(a, b) => std::cmp::max(Self::expr_phase(a), Self::expr_phase(b)), + } + } + + /// Return the storage phase of phase + pub(crate) fn storage_for_phase(phase: u8) -> CellType_ { + match phase { + 0 => CellType_::StoragePhase1, + 1 => CellType_::StoragePhase2, + _ => unreachable!(), + } + } + + /// Return the storage cell of the expression + pub(crate) fn storage_for_expr(expr: &Expression) -> CellType_ { + Self::storage_for_phase::(Self::expr_phase::(expr)) + } +} + +#[derive(Clone, Debug)] +pub(crate) struct CellColumn { + index: usize, + cell_type: CellType_, + height: usize, + expr: Expression, +} + + +impl Expr for CellColumn { + fn expr(&self) -> Expression { + self.expr.clone() + } +} #[derive(Clone, Debug)] pub struct CellManager { // Thoughts (Cecilia): Integrate CellManager's function into Halo2's VirtualCell From 5508767e67e16e80e079aa7478add8811fd3d794 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Tue, 23 May 2023 12:23:45 +0800 Subject: [PATCH 053/102] compiled in mpt --- zkevm-circuits/Cargo.toml | 10 +- .../src/circuit_tools/cached_region.rs | 26 +- .../src/circuit_tools/cell_manager.rs | 439 +++++------------- .../src/circuit_tools/constraint_builder.rs | 58 +-- zkevm-circuits/src/circuit_tools/gadgets.rs | 26 +- zkevm-circuits/src/circuit_tools/memory.rs | 26 +- zkevm-circuits/src/circuit_tools/table.rs | 84 +--- .../src/circuit_tools/tests/util.rs | 67 ++- .../src/circuit_tools/tests/util2.rs | 188 ++++++++ zkevm-circuits/src/evm_circuit/execution.rs | 2 + zkevm-circuits/src/evm_circuit/table.rs | 2 +- .../evm_circuit/util/math_gadget/test_util.rs | 2 +- zkevm-circuits/src/mpt_circuit.rs | 28 +- .../src/mpt_circuit/account_leaf.rs | 61 +-- zkevm-circuits/src/mpt_circuit/branch.rs | 18 +- zkevm-circuits/src/mpt_circuit/extension.rs | 22 +- .../src/mpt_circuit/extension_branch.rs | 26 +- zkevm-circuits/src/mpt_circuit/helpers.rs | 240 ++++++---- zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs | 61 ++- zkevm-circuits/src/mpt_circuit/start.rs | 22 +- .../src/mpt_circuit/storage_leaf.rs | 38 +- zkevm-circuits/src/mpt_circuit/table.rs | 30 +- zkevm-circuits/src/table.rs | 10 +- 23 files changed, 751 insertions(+), 735 deletions(-) create mode 100644 zkevm-circuits/src/circuit_tools/tests/util2.rs diff --git a/zkevm-circuits/Cargo.toml b/zkevm-circuits/Cargo.toml index 95cc868376..65a123ee4c 100644 --- a/zkevm-circuits/Cargo.toml +++ b/zkevm-circuits/Cargo.toml @@ -57,8 +57,14 @@ serde_json = "1.0.78" [features] -default = [] +default = ["test", "dev-graph"] test = ["ethers-signers", "mock"] test-circuits = [] warn-unimplemented = ["eth-types/warn-unimplemented"] -dev-graph = ["halo2_proofs/dev-graph", "plotters"] \ No newline at end of file +dev-graph = ["halo2_proofs/dev-graph", "plotters"] + +[[test]] +name = "test_circuit_tools" +path = "circuit_tools/tests/util.rs" +required-features = ["test", "dev-graph"] + diff --git a/zkevm-circuits/src/circuit_tools/cached_region.rs b/zkevm-circuits/src/circuit_tools/cached_region.rs index fed66b51f1..7649975777 100644 --- a/zkevm-circuits/src/circuit_tools/cached_region.rs +++ b/zkevm-circuits/src/circuit_tools/cached_region.rs @@ -1,5 +1,5 @@ use crate::{ - circuit_tools::cell_manager::{Cell, CellType_}, + circuit_tools::cell_manager::{Cell, EvmCellType}, }; use eth_types::{Field}; use halo2_proofs::{ @@ -12,7 +12,7 @@ use std::{ hash::{Hash, Hasher}, }; -use super::cell_manager::TableType; +use super::cell_manager::CellTypeTrait; pub trait ChallengeSet { fn indexed(&self) -> Vec<&Value>; @@ -24,20 +24,20 @@ impl]>> ChallengeSet for V { } } -pub struct CachedRegion<'r, 'b, F: Field, C: ChallengeSet> { +pub struct CachedRegion<'r, 'b, F: Field, S: ChallengeSet> { region: &'r mut Region<'b, F>, advice: Vec>, - challenges: &'r C, + challenges: &'r S, advice_columns: Vec>, width_start: usize, height_start: usize, } -impl<'r, 'b, F: Field, C: ChallengeSet> CachedRegion<'r, 'b, F, C> { +impl<'r, 'b, F: Field, S: ChallengeSet> CachedRegion<'r, 'b, F, S> { /// New cached region pub(crate) fn new( region: &'r mut Region<'b, F>, - challenges: &'r C, + challenges: &'r S, advice_columns: Vec>, height: usize, height_start: usize, @@ -140,7 +140,7 @@ impl<'r, 'b, F: Field, C: ChallengeSet> CachedRegion<'r, 'b, F, C> { [(((row_index - self.height_start) as i32) + rotation.0) as usize] } - pub fn challenges(&self) -> &C { + pub fn challenges(&self) -> &S { self.challenges } @@ -172,25 +172,25 @@ impl<'r, 'b, F: Field, C: ChallengeSet> CachedRegion<'r, 'b, F, C> { } #[derive(Debug, Clone)] -pub struct StoredExpression { +pub struct StoredExpression { pub(crate) name: String, cell: Cell, - cell_type: CellType_, + cell_type: C, expr: Expression, expr_id: String, } -impl Hash for StoredExpression { +impl Hash for StoredExpression { fn hash(&self, state: &mut H) { self.expr_id.hash(state); self.cell_type.hash(state); } } -impl StoredExpression { - pub fn assign>( +impl StoredExpression { + pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, ) -> Result, Error> { let value = self.expr.evaluate( diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index 858fe32453..0164219bcd 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -1,9 +1,10 @@ //! Cell manager +use crate::evm_circuit::table::Table; use crate::util::{Expr, query_expression}; -use crate::circuit_tools::{table::LookupTable, cached_region::{CachedRegion, ChallengeSet}}; +use crate::circuit_tools::{table::LookupTable_, cached_region::{CachedRegion, ChallengeSet}}; use eth_types::Field; -use halo2_proofs::plonk::{Any, SecondPhase, ThirdPhase, FirstPhase}; +use halo2_proofs::plonk::{Any, SecondPhase, ThirdPhase, FirstPhase, Phase}; use halo2_proofs::{ circuit::{AssignedCell, Value}, plonk::{ConstraintSystem, Advice, Column, Error, Expression, VirtualCells}, @@ -15,8 +16,6 @@ use std::fmt::Debug; use std::hash::Hash; use strum_macros::EnumIter; -use super::table::LookupTable_; - #[derive(Clone, Debug, Default)] pub(crate) struct Cell { // expression for constraint @@ -24,7 +23,6 @@ pub(crate) struct Cell { column: Option>, // relative position to selector for synthesis rotation: usize, - cell_column_index: usize, } @@ -33,20 +31,18 @@ impl Cell { meta: &mut VirtualCells, column: Column, rotation: usize, - cell_column_index: usize, ) -> Self { Self { expression: Some(meta.query_advice(column, Rotation(rotation as i32))), column: Some(column), rotation, - cell_column_index, } } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, value: F, ) -> Result, Error> { @@ -63,9 +59,9 @@ impl Cell { ) } - pub(crate) fn assign_value>( + pub(crate) fn assign_value>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, value: Value, ) -> Result, Error> { @@ -107,6 +103,27 @@ impl Expr for &Cell { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum EvmCellType { + StoragePhase1, + StoragePhase2, + StoragePermutation, + LookupByte, + Lookup(Table), +} + +impl Default for EvmCellType { + fn default() -> Self { + Self::StoragePhase1 + } +} + +impl CellTypeTrait for EvmCellType { + fn byte_type() -> Option { + Some(EvmCellType::LookupByte) + } +} + #[derive(Clone, Debug)] pub struct CellConfig { cell_type: C, @@ -115,23 +132,31 @@ pub struct CellConfig { is_permute: bool, } +impl From<(C, usize, u8, bool)> for CellConfig { + fn from((cell_type, num_columns, phase, is_permute): (C, usize, u8, bool)) -> Self { + Self { + cell_type, + num_columns, + phase, + is_permute, + } + } +} + impl CellConfig { pub fn init_columns(&self, meta: &mut ConstraintSystem) -> Vec>{ let mut columns = Vec::with_capacity(self.num_columns); - match self.phase { - 0 => columns.iter_mut() - .map(|c| *c = meta.advice_column_in(FirstPhase)) - .collect::>(), - 1 => columns.iter_mut() - .map(|c| *c = meta.advice_column_in(SecondPhase)) - .collect::>(), - 2 => columns.iter_mut() - .map(|c| *c = meta.advice_column_in(ThirdPhase)) - .collect::>(), - _ => unreachable!(), - }; + let _ = columns.iter_mut() + .map(|c| + match self.phase { + 0 => *c = meta.advice_column_in(FirstPhase), + 1 => *c = meta.advice_column_in(SecondPhase), + 2 => *c = meta.advice_column_in(ThirdPhase), + _ => unreachable!(), + } + ); if self.is_permute { - columns.iter().map(|c| meta.enable_equality(c.clone())); + let _ = columns.iter().map(|c| meta.enable_equality(c.clone())).collect::>(); } columns } @@ -139,9 +164,15 @@ impl CellConfig { pub trait CellTypeTrait: - Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash {} + Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash + Default { + fn byte_type() -> Option; + } + +/// this new cell manager has been in the planning for some time https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1203 +/// Chiquito has a cell manager that is more abstracted out even: https://github.com/privacy-scaling-explorations/chiquito/blob/main/src/compiler/cell_manager.rs + #[derive(Clone, Debug)] pub(crate) struct CellColumn_ { index: usize, @@ -153,20 +184,21 @@ pub(crate) struct CellColumn_ { #[derive(Clone, Debug)] pub struct CellManager_ { - max_height: usize, - total_width: usize, + // cell_type -> (start_width, cell_list) cells: HashMap>)>, cell_configs: Vec>, columns: Vec>, + offset: usize, + max_height: usize, + total_width: usize, } impl CellManager_ { - // 一步到位 - pub(crate) fn new>( + pub(crate) fn new( meta: &mut ConstraintSystem, - mut cell_configs: Vec>, - tables: Vec<&dyn LookupTable_>, + cell_configs: Vec<(C, usize, u8, bool)>, + tables: Vec<&dyn LookupTable_>, offset: usize, max_height: usize, ) -> Self { @@ -175,37 +207,29 @@ impl CellManager_ { let mut cell_columns = Vec::new(); let mut total_width = 0; + let mut cell_configs = cell_configs.into_iter().map(|c| c.into()).collect::>(); + // User need to put fixed columns after advice if have any // permutation is not enable by default for table in tables { - if !table.advice_columns().is_empty() { - cell_configs.push(CellConfig { - cell_type: table.get_type_().into(), - num_columns: table.advice_columns().len(), - phase: table.phase(), - is_permute: false, - }); - } - if !table.fixed_columns().is_empty() { - cell_configs.push(CellConfig { - cell_type: table.get_type_().into(), - num_columns: table.fixed_columns().len(), - phase: table.phase(), - is_permute: false, - }); - } + cell_configs.push(CellConfig { + cell_type: table.get_type_().into(), + num_columns: table.columns().len(), + phase: table.phase(), + is_permute: false, + }); }; cell_configs .iter() - .map(|c| { + .for_each(|c| { let cols = c.init_columns(meta); let mut cell_list = Vec::with_capacity(cols.len() * max_height); let start_width = total_width; query_expression(meta, |meta| { for w in 0..cols.len() { for h in 0..max_height { - let cell: Cell<_> = Cell::new(meta, cols[w], offset + h, total_width); + let cell: Cell<_> = Cell::new(meta, cols[w], offset + h); cell_list.push(cell); } cell_columns.push(CellColumn_ { @@ -218,14 +242,15 @@ impl CellManager_ { } }); cells.insert(c.cell_type, (start_width, cell_list)); - }).collect::>(); + }); Self { - max_height, - total_width, cells, cell_configs, columns: cell_columns, + offset, + max_height, + total_width, } } @@ -237,7 +262,28 @@ impl CellManager_ { self.max_height } - pub(crate) fn set_max_height(&mut self, max_height: usize) { + pub(crate) fn get_offset(&self) -> usize { + self.offset + } + + pub(crate) fn set_max_height(&mut self, meta: &mut VirtualCells, max_height: usize) { + if max_height > self.max_height { + self.cells.values_mut() + .enumerate() + .for_each(|(_, (_, cells))| { + let col = cells[0].column(); + let mut added_cells = (self.max_height..max_height) + .map(|h| Cell::new(meta, col, self.offset + h)) + .collect::>(); + cells.append(&mut added_cells); + } + ); + } else { + self.cells + .values_mut() + .enumerate() + .for_each(|(_, (_, cells))| cells.truncate(max_height)); + } self.max_height = max_height; } @@ -262,6 +308,13 @@ impl CellManager_ { self.columns[*start_width..window].to_owned() } + /// Clears columns record and set new height in cells array + /// query new cells if needed + pub(crate) fn reset(&mut self, meta: &mut VirtualCells, new_height: usize) { + self.columns.iter_mut().for_each(|c| c.height = 0); + self.set_max_height(meta, new_height); + } + pub(crate) fn query_cells(&mut self, cell_type: C, count: usize) -> Vec> { let mut targets = Vec::with_capacity(count); let (start_width, cell_list) = self.cells.get(&cell_type).expect("Cell type not found"); @@ -273,13 +326,13 @@ impl CellManager_ { self.columns[*start_width..start_width + window] .iter_mut() .enumerate() - .map(|(i, c)| { + .for_each(|(i, c)| { assert!(c.cell_type == cell_type); if c.height < self.max_height { targets.push(cell_list[i + c.height].clone()); c.height += 1; } - }).collect::>(); + }); } targets } @@ -289,279 +342,3 @@ impl CellManager_ { } } - - -// ============================== Old Version ================================= - - - - -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) enum CellType_ { - StoragePhase1, - StoragePhase2, - StoragePermutation, - LookupByte, - Lookup(T), -} - -impl Default for CellType_ { - fn default() -> Self { - CellType_::StoragePhase1 - } -} - -pub trait TableType: Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash {} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] -pub enum SingleTable { - Default, -} -impl TableType for SingleTable {} -/// Example - -// use super::table::{TestTableType, MptTable, BytecodeTable}; - -// fn work_like_this(meta: &mut ConstraintSystem) { -// let config: PhaseConfig = PhaseConfig::new( -// &[MptTable::construct(meta), BytecodeTable::construct(meta)], -// 2, -// 3 -// ); -// } - - -impl CellType_ { - // The phase that given `Expression` becomes evaluateable. - fn expr_phase(expr: &Expression) -> u8 { - use Expression::*; - match expr { - Challenge(challenge) => challenge.phase() + 1, - Advice(query) => query.phase(), - Constant(_) | Selector(_) | Fixed(_) | Instance(_) => 0, - Negated(a) | Expression::Scaled(a, _) => Self::expr_phase(a), - Sum(a, b) | Product(a, b) => std::cmp::max(Self::expr_phase(a), Self::expr_phase(b)), - } - } - - /// Return the storage phase of phase - pub(crate) fn storage_for_phase(phase: u8) -> CellType_ { - match phase { - 0 => CellType_::StoragePhase1, - 1 => CellType_::StoragePhase2, - _ => unreachable!(), - } - } - - /// Return the storage cell of the expression - pub(crate) fn storage_for_expr(expr: &Expression) -> CellType_ { - Self::storage_for_phase::(Self::expr_phase::(expr)) - } -} - -#[derive(Clone, Debug)] -pub(crate) struct CellColumn { - index: usize, - cell_type: CellType_, - height: usize, - expr: Expression, -} - - -impl Expr for CellColumn { - fn expr(&self) -> Expression { - self.expr.clone() - } -} -#[derive(Clone, Debug)] -pub struct CellManager { - // Thoughts (Cecilia): Integrate CellManager's function into Halo2's VirtualCell - // They do the same things by saving queried Exressions - // CM is just slightly smarter. - // Make VC into trait, let CM impl VC. - pub(crate) width: usize, - pub(crate) height: usize, - pub(crate) cells: Vec>, - // 对cell的抽象表示和对columns的抽象表示是分开的 - // Cell 不用 T - pub(crate) columns: Vec>, - pub(crate) phase_config: PhaseConfig, - pub(crate) copy_columns: usize, -} - -#[derive(Clone, Debug)] -pub struct PhaseConfig { - phase1: usize, - phase2: usize, - phase3: Vec<(T, usize)>, //lookup -} - -impl PhaseConfig { - pub fn new( - phase1: usize, - phase2: usize, - tables: Vec<&dyn LookupTable> - ) -> Self { - let phase3 = tables.iter().map(|t| - (t.get_type(), t.columns().len()) - ).collect::>(); - Self { - phase1, - phase2, - phase3, - } - } -} - -impl CellManager { - - - pub(crate) fn new( - meta: &mut ConstraintSystem, // meta只出现一次,new的时候把所有cover的cells都query一遍 - height: usize, // 拿到 Expr 存起来,后面 cb.query_cell 直接给对应格子的 Expr - advices: &[Column], - height_offset: usize, - phase_config: PhaseConfig, - copy_columns: usize, - ) -> Self { - // Setup the columns and query the cells - let width = advices.len(); - let mut cells = Vec::with_capacity(height * width); - let mut columns = Vec::with_capacity(width); - - // 这个是meta.create_gate的替代 - // 主要是想 query 新的 column - // 在会加一个0.expr()为constraint,因为里面调的create_gate要求 - query_expression(meta, |meta| { - for c in 0..width { - for r in 0..height { - cells.push(Cell::new(meta, advices[c], height_offset + r, c)); - } - columns.push(CellColumn { - index: c, - cell_type: CellType_::StoragePhase1, - height: 0, - expr: cells[c * height].expr(), - }); - } - }); - - let mut column_idx = 0; - - - // Mark columns used for byte lookup - for _ in 0..phase_config.phase1 { - assert_eq!(advices[column_idx].column_type().phase(), 0); - column_idx += 1; - } - - // Mark columns used for Phase2 constraints - for _ in 0..phase_config.phase2 { - assert_eq!(advices[column_idx].column_type().phase(), 1u8); - columns[column_idx].cell_type = CellType_::StoragePhase2; - column_idx += 1; - } - - // Mark columns used for lookups in Phase3 - for (table, count) in &phase_config.phase3 { - for _ in 0usize..*count { - assert_eq!(advices[column_idx].column_type().phase(), 2u8); - columns[column_idx].cell_type = CellType_::Lookup(*table); - column_idx += 1; - } - } - - // Mark columns used for copy constraints - for _ in 0..copy_columns { - meta.enable_equality(advices[column_idx]); - columns[column_idx].cell_type = CellType_::StoragePermutation; - column_idx += 1; - } - - - Self { - width, - height, - cells, - columns, - phase_config, - copy_columns, - } - } - - pub(crate) fn query_cells(&mut self, cell_type: CellType_, count: usize) -> Vec> { - let mut cells = Vec::with_capacity(count); - while cells.len() < count { - let column_idx = self.next_column(cell_type); - let column = &mut self.columns[column_idx]; - cells.push(self.cells[column_idx * self.height + column.height].clone()); - column.height += 1; - } - cells - } - - pub(crate) fn query_cell(&mut self, cell_type: CellType_) -> Cell { - self.query_cells(cell_type, 1)[0].clone() - } - - pub(crate) fn reset(&mut self, height: usize) { - assert!(height <= self.height); - self.height = height; - for column in self.columns.iter_mut() { - column.height = 0; - } - } - - fn next_column(&self, cell_type: CellType_) -> usize { - let mut best_index: Option = None; - let mut best_height = self.height; - for column in self.columns.iter() { - if column.cell_type == cell_type && column.height < best_height { - best_index = Some(column.index); - best_height = column.height; - } - } - // Replace a CellType_::Storage by CellType_::StoragePermutation if the later has - // better height - if cell_type == CellType_::StoragePhase1 { - for column in self.columns.iter() { - if column.cell_type == CellType_::StoragePermutation && column.height < best_height { - best_index = Some(column.index); - best_height = column.height; - } - } - } - match best_index { - Some(index) => index, - // If we reach this case, it means that all the columns of cell_type have assignments - // taking self.height rows, so there's no more space. - None => panic!("not enough cells for query: {:?}", cell_type), - } - } - - pub(crate) fn get_height(&self) -> usize { - self.columns - .iter() - .map(|column| column.height) - .max() - .unwrap() - } - - /// Returns a map of CellType -> (width, height, num_cells) - pub(crate) fn get_stats(&self) -> BTreeMap, (usize, usize, usize)> { - let mut data = BTreeMap::new(); - for column in self.columns.iter() { - let (mut count, mut height, mut num_cells) = - data.get(&column.cell_type).unwrap_or(&(0, 0, 0)); - count += 1; - height = height.max(column.height); - num_cells += column.height; - data.insert(column.cell_type, (count, height, num_cells)); - } - data - } - - pub(crate) fn columns(&self) -> &[CellColumn] { - &self.columns - } -} \ No newline at end of file diff --git a/zkevm-circuits/src/circuit_tools/constraint_builder.rs b/zkevm-circuits/src/circuit_tools/constraint_builder.rs index 94af725a47..5ad2423c66 100644 --- a/zkevm-circuits/src/circuit_tools/constraint_builder.rs +++ b/zkevm-circuits/src/circuit_tools/constraint_builder.rs @@ -7,7 +7,7 @@ use gadgets::util::{and, sum, Scalar}; use halo2_proofs::plonk::{ConstraintSystem, Expression}; use itertools::Itertools; -use super::cell_manager::{Cell, CellManager, CellType_, TableType}; +use super::cell_manager::{Cell, CellManager_, CellTypeTrait, EvmCellType}; /// Lookup data #[derive(Clone)] @@ -24,7 +24,7 @@ pub struct LookupData { /// Constraint builder #[derive(Clone)] -pub struct ConstraintBuilder { +pub struct ConstraintBuilder { constraints: Vec<(&'static str, Expression)>, max_degree: usize, conditions: Vec>, @@ -33,11 +33,11 @@ pub struct ConstraintBuilder { /// The lookup tables pub lookup_tables: Vec>, /// CellManager - pub cell_manager: Option>, + pub cell_manager: Option>, } -impl ConstraintBuilder { - pub(crate) fn new(max_degree: usize, cell_manager: Option>) -> Self { +impl ConstraintBuilder { + pub(crate) fn new(max_degree: usize, cell_manager: Option>) -> Self { ConstraintBuilder { constraints: Vec::new(), max_degree, @@ -48,7 +48,7 @@ impl ConstraintBuilder { } } - pub(crate) fn set_cell_manager(&mut self, cell_manager: CellManager) { + pub(crate) fn set_cell_manager(&mut self, cell_manager: CellManager_) { self.cell_manager = Some(cell_manager); } @@ -119,40 +119,32 @@ impl ConstraintBuilder { // Query pub(crate) fn query_bool(&mut self) -> Cell { - let cell = self.query_cell(); + let cell = self.query_default(); self.require_boolean("Constrain cell to be a bool", cell.expr()); cell } - pub(crate) fn query_byte(&mut self) -> Cell { - // TODO(Brecht): fix - self.query_cell_with_type(CellType_::StoragePhase1) + pub(crate) fn query_default(&mut self) -> Cell { + self.query_cells_dyn(C::default(), 1) + .get(0) + .expect("No cell found") + .clone() } - pub(crate) fn query_bytes(&mut self) -> [Cell; N] { - self.query_bytes_dyn(N).try_into().unwrap() - } - - pub(crate) fn query_bytes_dyn(&mut self, count: usize) -> Vec> { - self.query_cells_dyn(CellType_::StoragePhase1, count) - } - - pub(crate) fn query_cell(&mut self) -> Cell { - self.query_cell_with_type(CellType_::StoragePhase1) + pub(crate) fn query_one(&mut self, cell_type: C) -> Cell { + self.query_cells_dyn(cell_type, 1).first().unwrap().clone() } - pub(crate) fn query_cells(&mut self) -> [Cell; N] { - self.query_cells_dyn(CellType_::StoragePhase1, N) - .try_into() + pub(crate) fn query_bytes(&mut self) -> [Cell; N] { + // Your own definition of CellType::Byte + self.query_cells_dyn( + C::byte_type().expect("No byte type for this CellManager"), + N + ).try_into() .unwrap() } - pub(crate) fn query_cell_with_type(&mut self, cell_type: CellType_) -> Cell { - self.query_cells_dyn(cell_type, 1).first().unwrap().clone() - } - - fn query_cells_dyn(&mut self, cell_type: CellType_, count: usize) -> Vec> { - // cb 对 cm 仅有一个调度接口,即 query_cells + pub(crate) fn query_cells_dyn(&mut self, cell_type: C, count: usize) -> Vec> { self.cell_manager .as_mut() .expect("Cell manager not set") @@ -327,8 +319,8 @@ impl ConstraintBuilder { } } -pub(crate) fn merge_lookups( - cb: &mut ConstraintBuilder, +pub(crate) fn merge_lookups( + cb: &mut ConstraintBuilder, lookups: Vec>, ) -> (Expression, Vec>) { merge_values( @@ -340,8 +332,8 @@ pub(crate) fn merge_lookups( ) } -pub(crate) fn merge_values( - cb: &mut ConstraintBuilder, +pub(crate) fn merge_values( + cb: &mut ConstraintBuilder, values: Vec<(Expression, Vec>)>, ) -> (Expression, Vec>) { let selector = sum::expr(values.iter().map(|(condition, _)| condition.expr())); diff --git a/zkevm-circuits/src/circuit_tools/gadgets.rs b/zkevm-circuits/src/circuit_tools/gadgets.rs index 5727480491..236af96a32 100644 --- a/zkevm-circuits/src/circuit_tools/gadgets.rs +++ b/zkevm-circuits/src/circuit_tools/gadgets.rs @@ -7,7 +7,7 @@ use halo2_proofs::{ use crate::evm_circuit::util::{from_bytes, pow_of_two}; -use super::{cell_manager::{Cell, TableType}, constraint_builder::ConstraintBuilder, cached_region::{CachedRegion, ChallengeSet}}; +use super::{cell_manager::{Cell, CellTypeTrait}, constraint_builder::ConstraintBuilder, cached_region::{CachedRegion, ChallengeSet}}; /// Returns `1` when `value == 0`, and returns `0` otherwise. #[derive(Clone, Debug, Default)] @@ -17,9 +17,9 @@ pub struct IsZeroGadget { } impl IsZeroGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, value: Expression) -> Self { + pub(crate) fn construct(cb: &mut ConstraintBuilder, value: Expression) -> Self { circuit!([meta, cb], { - let inverse = cb.query_cell(); + let inverse = cb.query_default(); let is_zero = 1.expr() - (value.expr() * inverse.expr()); // `value != 0` => check `inverse = a.invert()`: value * (1 - value * inverse) @@ -38,9 +38,9 @@ impl IsZeroGadget { self.is_zero.as_ref().unwrap().clone() } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, value: F, ) -> Result { @@ -61,8 +61,8 @@ pub struct IsEqualGadget { } impl IsEqualGadget { - pub(crate) fn construct( - cb: &mut ConstraintBuilder, + pub(crate) fn construct( + cb: &mut ConstraintBuilder, lhs: Expression, rhs: Expression, ) -> Self { @@ -75,9 +75,9 @@ impl IsEqualGadget { self.is_zero.expr() } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, lhs: F, rhs: F, @@ -104,8 +104,8 @@ pub struct LtGadget { } impl LtGadget { - pub(crate) fn construct( - cb: &mut ConstraintBuilder, + pub(crate) fn construct( + cb: &mut ConstraintBuilder, lhs: Expression, rhs: Expression, ) -> Self { @@ -131,9 +131,9 @@ impl LtGadget { self.lt.as_ref().unwrap().expr() } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, lhs: F, rhs: F, diff --git a/zkevm-circuits/src/circuit_tools/memory.rs b/zkevm-circuits/src/circuit_tools/memory.rs index 8e8f57e0f5..cd157164b2 100644 --- a/zkevm-circuits/src/circuit_tools/memory.rs +++ b/zkevm-circuits/src/circuit_tools/memory.rs @@ -11,7 +11,7 @@ use std::{ ops::{Index, IndexMut}, }; -use super::{constraint_builder::ConstraintBuilder, cell_manager::TableType}; +use super::{constraint_builder::ConstraintBuilder, cell_manager::CellTypeTrait}; #[derive(Clone, Debug, Default)] pub(crate) struct Memory { @@ -55,9 +55,9 @@ impl Memory { unreachable!() } - pub(crate) fn generate_constraints( + pub(crate) fn generate_constraints( &self, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, is_first_row: Expression, ) { for bank in self.banks.iter() { @@ -150,29 +150,29 @@ impl MemoryBank { self.cur.expr() } - pub(crate) fn load( + pub(crate) fn load( &self, description: &'static str, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, offset: Expression, values: &[Expression], ) { self.load_with_key(description, cb, self.key() - offset, values); } - pub(crate) fn load_with_key( + pub(crate) fn load_with_key( &self, description: &'static str, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, key: Expression, values: &[Expression], ) { cb.lookup(description, self.tag(), self.insert_key(key, values)); } - pub(crate) fn store( + pub(crate) fn store( &self, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, values: &[Expression], ) -> Expression { let key = self.key() + 1.expr(); @@ -180,9 +180,9 @@ impl MemoryBank { key } - pub(crate) fn store_with_key( + pub(crate) fn store_with_key( &self, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, key: Expression, values: &[Expression], ) { @@ -202,9 +202,9 @@ impl MemoryBank { self.store_offsets.clear(); } - pub(crate) fn generate_constraints( + pub(crate) fn generate_constraints( &self, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, is_first_row: Expression, ) { let lookup_table = cb.get_lookup_table(self.tag()); diff --git a/zkevm-circuits/src/circuit_tools/table.rs b/zkevm-circuits/src/circuit_tools/table.rs index e08ba30341..3c51f3fb2e 100644 --- a/zkevm-circuits/src/circuit_tools/table.rs +++ b/zkevm-circuits/src/circuit_tools/table.rs @@ -5,71 +5,21 @@ use halo2_proofs::{ poly::Rotation, }; +use super::{cell_manager::{CellTypeTrait, EvmCellType}}; -use super::{cell_manager::{TableType, SingleTable}}; -/// Trait used to define lookup tables -pub trait LookupTable { - - fn get_type(&self) -> T; - - /// Returns the list of ALL the table columns following the table order. - fn columns(&self) -> Vec>; - - /// Returns the list of ALL the table advice columns following the table - /// order. - fn advice_columns(&self) -> Vec> { - self.columns() - .iter() - .map(|&col| col.try_into()) - .filter_map(|res| res.ok()) - .collect() - } - - /// Returns the list of ALL the table fixed columns following the table - /// order. - fn fixed_columns(&self) -> Vec> { - self.columns() - .iter() - .map(|&col| col.try_into()) - .filter_map(|res| res.ok()) - .collect() - } - - /// Returns the String annotations associated to each column of the table. - fn annotations(&self) -> Vec; - - /// Return the list of expressions used to define the lookup table. - fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { - self.columns() - .iter() - .map(|&column| meta.query_any(column, Rotation::cur())) - .collect() - } +/// LookupTable impl for raw columns. +/// Must define a existing CellType to instantiate this impelmentation +impl> + Copy, const W: usize> LookupTable_ for [CA; W] { + type TableCellType = EvmCellType; - /// Annotates a lookup table by passing annotations for each of it's - /// columns. - fn annotate_columns(&self, cs: &mut ConstraintSystem) { - self.columns() - .iter() - .zip(self.annotations().iter()) - .for_each(|(&col, ann)| cs.annotate_lookup_any_column(col, || ann)) - } - - /// Annotates columns of a table embedded within a circuit region. - fn annotate_columns_in_region(&self, region: &mut Region) { - self.columns() - .iter() - .zip(self.annotations().iter()) - .for_each(|(&col, ann)| region.name_column(|| ann, col)) + fn get_type_(&self) -> EvmCellType { + EvmCellType::default() } -} - -impl> + Copy, const W: usize> LookupTable for [C; W] { - - fn get_type(&self) -> SingleTable { - SingleTable::Default + fn phase(&self) -> u8 { + // default phase is 0 + 0 } fn table_exprs(&self, meta: &mut VirtualCells) -> Vec> { @@ -90,9 +40,9 @@ impl> + Copy, const W: usize> LookupTable { - type TableType_; + type TableCellType; - fn get_type_(&self) -> Self::TableType_; + fn get_type_(&self) -> Self::TableCellType; fn phase(&self) -> u8; @@ -109,16 +59,6 @@ pub trait LookupTable_ { .collect() } - /// Returns the list of ALL the table fixed columns following the table - /// order. - fn fixed_columns(&self) -> Vec> { - self.columns() - .iter() - .map(|&col| col.try_into()) - .filter_map(|res| res.ok()) - .collect() - } - /// Returns the String annotations associated to each column of the table. fn annotations(&self) -> Vec; diff --git a/zkevm-circuits/src/circuit_tools/tests/util.rs b/zkevm-circuits/src/circuit_tools/tests/util.rs index 3367a35d2e..4c15a43fe9 100644 --- a/zkevm-circuits/src/circuit_tools/tests/util.rs +++ b/zkevm-circuits/src/circuit_tools/tests/util.rs @@ -2,11 +2,11 @@ use std::rc::Rc; use std::vec; use crate::circuit_tools::cached_region::{self, ChallengeSet}; -use crate::circuit_tools::cell_manager::{Cell, CellManager, PhaseConfig, SingleTable, TableType, CellType_}; +use crate::circuit_tools::cell_manager::{Cell, CellManager_, CellTypeTrait}; use crate::circuit_tools::constraint_builder::ConstraintBuilder; use crate::circuit_tools::memory::Memory; use crate::util::{Expr, query_expression}; -use crate::circuit_tools::{table::LookupTable, cached_region::CachedRegion}; +use crate::circuit_tools::{table::LookupTable_, cached_region::CachedRegion}; use eth_types::Field; use gadgets::util::Scalar; @@ -39,10 +39,36 @@ pub struct TestTable { pub b: Column, } -impl LookupTable for TestTable { - fn get_type(&self) -> SingleTable { - SingleTable::Default +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum CellType { + LookupTestTable, + PhaseOne, + PhaseTwo +} + +impl Default for CellType { + fn default() -> Self { + CellType::PhaseOne + } +} + +impl CellTypeTrait for CellType { + fn byte_type() -> Option { + Some(CellType::PhaseOne) + } +} + +impl LookupTable_ for TestTable { + type TableCellType = CellType; + + fn get_type_(&self) -> CellType { + CellType::LookupTestTable } + + fn phase(&self) -> u8 { + 1 + } + fn columns(&self) -> Vec> { vec![self.a.into(), self.b.into()] } @@ -85,9 +111,18 @@ impl TestConfig { ).collect::>(); // Init cell manager and constraint builder - let phase_config: PhaseConfig = PhaseConfig::new::(3, 3, vec![&table]); - let mut cm = CellManager::new(meta, CM_HEIGHT,&cell_columns,0,phase_config,COPY_COL_NUM ); - let mut cb: ConstraintBuilder = ConstraintBuilder::new(MAX_DEG, Some(cm)); + let mut cm = CellManager_::new( + meta, + vec![ + (CellType::PhaseOne, 3, 0, false), + (CellType::PhaseTwo, 3, 0, false), + (CellType::LookupTestTable, 3, 0, false), + ], + vec![&table], + 0, + 10 + ); + let mut cb: ConstraintBuilder = ConstraintBuilder::new(MAX_DEG, Some(cm)); let mut cell_gadget = CellGadget::default(); meta.create_gate("Test Gate", |meta| { @@ -172,7 +207,7 @@ impl TestConfig { #[derive(Clone, Debug, Default)] pub struct CellGadget { // (a, b) in lookup - // a + r1 * b == c + // a, r1 * b == c // where r1 is phase1 challenge // a == d a: Cell, @@ -183,12 +218,12 @@ pub struct CellGadget { impl CellGadget { - pub fn configure(cb: &mut ConstraintBuilder, r1: Expression) -> Self { - let a = cb.query_cell(); - let b = cb.query_cell(); + pub fn configure(cb: &mut ConstraintBuilder, r1: Expression) -> Self { + let a = cb.query_default(); + let b = cb.query_default(); // c depends on Phase1 Challenge r1 - let c = cb.query_cell_with_type(CellType_::StoragePhase2); - let d = cb.query_cell(); + let c = cb.query_one(CellType::PhaseTwo); + let d = cb.query_default(); circuit!([meta, cb], { require!((a, b) => @format!("test_lookup")); require!(c => a.expr() + b.expr() * r1); @@ -198,9 +233,9 @@ impl CellGadget { CellGadget { a, b, c, d } } - pub fn assign>( + pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, ) -> Result<(), Error>{ diff --git a/zkevm-circuits/src/circuit_tools/tests/util2.rs b/zkevm-circuits/src/circuit_tools/tests/util2.rs new file mode 100644 index 0000000000..5c8c8265fc --- /dev/null +++ b/zkevm-circuits/src/circuit_tools/tests/util2.rs @@ -0,0 +1,188 @@ +use std::marker::PhantomData; +use std::rc::Rc; +use std::vec; + +use crate::circuit_tools::cached_region::{self, ChallengeSet}; +use crate::circuit_tools::cell_manager::{Cell, CellManager, PhaseConfig, SingleTable, TableType, EvmCellType}; +use crate::circuit_tools::constraint_builder::ConstraintBuilder; +use crate::circuit_tools::memory::Memory; +use crate::util::{Expr, query_expression}; +use crate::circuit_tools::{table::LookupTable, cached_region::CachedRegion}; + +use eth_types::Field; +use gadgets::util::Scalar; +use halo2_proofs::circuit::layouter::RegionColumn; +use halo2_proofs::circuit::{SimpleFloorPlanner, layouter, Layouter, Region}; +use halo2_proofs::dev::MockProver; +use halo2_proofs::halo2curves::bn256::Fr; +use halo2_proofs::plonk::{Any, Circuit, FirstPhase, Challenge, SecondPhase, ThirdPhase, Fixed, Selector}; +use halo2_proofs::{ + circuit::{AssignedCell, Value}, + plonk::{ConstraintSystem, Advice, Column, Error, Expression, VirtualCells}, + poly::Rotation, +}; + + + + +#[derive(Clone)] +pub struct TestConfig { + pub q_usable: Selector, + pub a: Column, + pub b: Column, + pub c: Column, + pub d: Column, + pub e: Column, + _phantom: PhantomData +} + + +impl TestConfig { + pub fn new( + meta: &mut ConstraintSystem, + // r1: Challenge + ) -> Self { + + // Get columns + let q_usable = meta.selector(); + let a = meta.advice_column(); + let b = meta.advice_column(); + let c = meta.advice_column(); + let d = meta.advice_column(); + let e = meta.advice_column(); + + meta.create_gate("Test Gate", |meta: &mut VirtualCells| { + + let mut exprs = Vec::new(); + let q = meta.query_selector(q_usable); + + let a1 = meta.query_advice(a, Rotation(0)); + let b1 = meta.query_advice(b, Rotation(0)); + let c1 = meta.query_advice(c, Rotation(0)); + exprs.push((a1*b1 - c1) * q.clone()); + + let b2 = meta.query_advice(b, Rotation(1)); + let c2 = meta.query_advice(c, Rotation(1)); + let d2 = meta.query_advice(d, Rotation(1)); + exprs.push((b2*c2 - d2) * q.clone()); + + let c3 = meta.query_advice(c, Rotation(2)); + let d3 = meta.query_advice(d, Rotation(2)); + let e3 = meta.query_advice(e, Rotation(2)); + exprs.push((c3*d3 - e3) * q.clone()); + + exprs + }); + + Self { + q_usable, + a, b, c, d, e, + _phantom: PhantomData + } + } + + pub fn assign( + &self, + layouter: &mut impl Layouter, + // r1: Value, + ) -> Result<(), Error> { + layouter.assign_region( + || "Test Region", + |mut region| { + self.q_usable.enable(&mut region, "q_usable_0", 0); + + region.name_column(|| "a", self.a); + region.name_column(|| "b", self.b); + region.name_column(|| "c", self.c); + region.name_column(|| "d", self.d); + region.name_column(|| "e", self.e); + + + + assign!(region, (self.a, 0) => 2.scalar())?; + assign!(region, (self.b, 0) => 3.scalar())?; + assign!(region, (self.c, 0) => 6.scalar())?; + + assign!(region, (self.b, 1) => 4.scalar())?; + assign!(region, (self.c, 1) => 5.scalar())?; + assign!(region, (self.d, 1) => 20.scalar())?; + + assign!(region, (self.c, 2) => 7.scalar())?; + assign!(region, (self.d, 2) => 8.scalar())?; + assign!(region, (self.e, 2) => 56.scalar())?; + + Ok(()) + }, + ) + } +} + + +#[derive(Clone, Debug, Default)] +struct TestCircuit { + // Don't need anything in this struct, + // since we don't have precomputed data from outside + // and Config & Challenges are passed to synthesize. + _phantom: F, +} + +impl Circuit for TestCircuit { + type Config = TestConfig; + type FloorPlanner = SimpleFloorPlanner; + + + fn without_witnesses(&self) -> Self { + unimplemented!() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let _dummy_phase1 = meta.advice_column(); + let r1 = meta.challenge_usable_after(FirstPhase); + + let config = TestConfig::new(meta); + config + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl halo2_proofs::circuit::Layouter + ) -> Result<(), Error> { + // let r1 = layouter.get_challenge(r1); + config.assign(&mut layouter) + } +} + +#[test] +fn test() { + let circuit = TestCircuit::::default(); + let prover = MockProver::::run(5, &circuit, vec![]).unwrap(); + prover.assert_satisfied_par(); + +} + +#[cfg(feature = "dev-graph")] +#[test] +fn test_graph() { + use plotters::prelude::*; + + let circuit = TestCircuit::::default(); + + println!("Start graphing"); + + let root = BitMapBackend::new("test.png", (512, 1024)).into_drawing_area(); + root.fill(&WHITE).unwrap(); + let root = root.titled("Test Chip Layout", ("sans-serif", 60)).unwrap(); + + halo2_proofs::dev::CircuitLayout::default() + .show_labels(true) + .show_equality_constraints(true) + .render(4, &circuit, &root) + .unwrap(); + + // Generate the DOT graph string. + let dot_string = halo2_proofs::dev::circuit_dot_graph(&circuit); + print!("{}", dot_string); + + +} diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index 58af4bfe3d..ab219e893a 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -832,6 +832,8 @@ impl ExecutionConfig { for column in cell_manager.columns().iter() { if let CellType::LookupByte = column.cell_type { meta.lookup_any("Byte lookup", |meta| { + // 只取第一位,其他都是rlc with challenge + // 😯 这里本来就只有一列range lookup let byte_table_expression = byte_table.table_exprs(meta)[0].clone(); vec![(column.expr(), byte_table_expression)] }); diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index c9eab33f0a..e046703153 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -122,7 +122,7 @@ impl FixedTableTag { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] -pub(crate) enum Table { +pub enum Table { Fixed, Tx, Rw, diff --git a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs index cb0a2ad326..8fbef0f15f 100644 --- a/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs +++ b/zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs @@ -13,7 +13,7 @@ use crate::{ }, Advice, Column, Fixed, }, - circuit_tools::table::LookupTable, + circuit_tools::table::LookupTable_, util::Challenges, }; use eth_types::{Field, Word, U256}; diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 98744a5aae..c500b87751 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -28,12 +28,11 @@ use self::{ account_leaf::AccountLeafConfig, helpers::{key_memory, RLPItemView}, witness_row::{StartRowType,ExtensionBranchRowType, AccountRowType, StorageRowType,Node}, - table::Table, }; use crate::{ assign, assignf, circuit, circuit_tools::{ - constraint_builder::ConstraintBuilder, memory::Memory, + memory::Memory, cached_region::CachedRegion, }, mpt_circuit::{ @@ -41,7 +40,7 @@ use crate::{ start::StartConfig, storage_leaf::StorageLeafConfig, }, - circuit_tools::{table::LookupTable, cell_manager::PhaseConfig}, + circuit_tools::{table::LookupTable_, cell_manager::{CellManager_, CellTypeTrait, EvmCellType}}, table::{KeccakTable, MPTProofType, MptTable}, util::Challenges, }; @@ -102,7 +101,7 @@ impl MPTContext { pub(crate) fn rlp_item( &self, meta: &mut VirtualCells, - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, idx: usize, ) -> RLPItemView { // TODO(Brecht): Add RLP limitations like max num bytes @@ -112,7 +111,7 @@ impl MPTContext { pub(crate) fn nibbles( &self, meta: &mut VirtualCells, - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, idx: usize, ) -> RLPItemView { self.rlp_item.create_view(meta, cb, idx, true) @@ -214,13 +213,24 @@ impl MPTConfig { memory: memory.clone(), }; - let _phase_config = PhaseConfig::new::(2, 2, vec![&keccak_table]); - - let mut cb = MPTConstraintBuilder::new(33 + 10, None); + let mut cm = CellManager_::new( + meta, + vec![ + (EvmCellType::StoragePhase1, 10, 0, false), + (EvmCellType::StoragePhase2, 10, 1, false), + (EvmCellType::LookupByte, 32, 0, false), + ], + vec![ + &keccak_table, &fixed_table + ], + 0, + 32 + ); + let mut cb = MPTConstraintBuilder::new(33 + 10, Some(cm)); meta.create_gate("MPT", |meta| { circuit!([meta, cb.base], { // Populate lookup tables - require!(@"keccak" => >::advice_columns(&keccak_table).iter().map(|table| a!(table)).collect()); + require!(@"keccak" => >::advice_columns(&keccak_table).iter().map(|table| a!(table)).collect()); require!(@"fixed" => fixed_table.iter().map(|table| f!(table)).collect()); ifx!{f!(q_enable) => { diff --git a/zkevm-circuits/src/mpt_circuit/account_leaf.rs b/zkevm-circuits/src/mpt_circuit/account_leaf.rs index 2994f50aa0..2ee5f6b8fb 100644 --- a/zkevm-circuits/src/mpt_circuit/account_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/account_leaf.rs @@ -15,7 +15,7 @@ use super::{ use crate::{ circuit, circuit_tools::{ - cell_manager::Cell, + cell_manager::{Cell, EvmCellType}, constraint_builder::{RLCChainable, RLCable, RLCableValue}, gadgets::IsEqualGadget, cached_region::{CachedRegion, ChallengeSet}, }, @@ -58,42 +58,43 @@ impl AccountLeafConfig { ) -> Self { let r = ctx.r.clone(); - cb.base + cb + .base .cell_manager .as_mut() .unwrap() - .reset(AccountRowType::Count as usize); + .reset(meta, AccountRowType::Count as usize); let mut config = AccountLeafConfig::default(); - circuit!([meta, cb.base], { + circuit!([meta, cb], { let key_items = [ - ctx.rlp_item(meta, &mut cb.base, AccountRowType::KeyS as usize), - ctx.rlp_item(meta, &mut cb.base, AccountRowType::KeyC as usize), + ctx.rlp_item(meta, cb, AccountRowType::KeyS as usize), + ctx.rlp_item(meta, cb, AccountRowType::KeyC as usize), ]; - config.value_rlp_bytes = [cb.base.query_bytes(), cb.base.query_bytes()]; - config.value_list_rlp_bytes = [cb.base.query_bytes(), cb.base.query_bytes()]; + config.value_rlp_bytes = [cb.query_bytes(), cb.query_bytes()]; + config.value_list_rlp_bytes = [cb.query_bytes(), cb.query_bytes()]; let nonce_items = [ - ctx.rlp_item(meta, &mut cb.base, AccountRowType::NonceS as usize), - ctx.rlp_item(meta, &mut cb.base, AccountRowType::NonceC as usize), + ctx.rlp_item(meta, cb, AccountRowType::NonceS as usize), + ctx.rlp_item(meta, cb, AccountRowType::NonceC as usize), ]; let balance_items = [ - ctx.rlp_item(meta, &mut cb.base, AccountRowType::BalanceS as usize), - ctx.rlp_item(meta, &mut cb.base, AccountRowType::BalanceC as usize), + ctx.rlp_item(meta, cb, AccountRowType::BalanceS as usize), + ctx.rlp_item(meta, cb, AccountRowType::BalanceC as usize), ]; let storage_items = [ - ctx.rlp_item(meta, &mut cb.base, AccountRowType::StorageS as usize), - ctx.rlp_item(meta, &mut cb.base, AccountRowType::StorageC as usize), + ctx.rlp_item(meta, cb, AccountRowType::StorageS as usize), + ctx.rlp_item(meta, cb, AccountRowType::StorageC as usize), ]; let codehash_items = [ - ctx.rlp_item(meta, &mut cb.base, AccountRowType::CodehashS as usize), - ctx.rlp_item(meta, &mut cb.base, AccountRowType::CodehashC as usize), + ctx.rlp_item(meta, cb, AccountRowType::CodehashS as usize), + ctx.rlp_item(meta, cb, AccountRowType::CodehashC as usize), ]; - let drifted_bytes = ctx.rlp_item(meta, &mut cb.base, AccountRowType::Drifted as usize); - let wrong_bytes = ctx.rlp_item(meta, &mut cb.base, AccountRowType::Wrong as usize); + let drifted_bytes = ctx.rlp_item(meta, cb, AccountRowType::Drifted as usize); + let wrong_bytes = ctx.rlp_item(meta, cb, AccountRowType::Wrong as usize); config.main_data = MainData::load( "main storage", - &mut cb.base, + cb, &ctx.memory[main_memory()], 0.expr(), ); @@ -110,24 +111,24 @@ impl AccountLeafConfig { for is_s in [true, false] { // Key data let key_data = &mut config.key_data[is_s.idx()]; - *key_data = KeyData::load(&mut cb.base, &ctx.memory[key_memory(is_s)], 0.expr()); + *key_data = KeyData::load(cb, &ctx.memory[key_memory(is_s)], 0.expr()); // Parent data let parent_data = &mut config.parent_data[is_s.idx()]; *parent_data = ParentData::load( "account load", - &mut cb.base, + cb, &ctx.memory[parent_memory(is_s)], 0.expr(), ); // Placeholder leaf checks config.is_in_empty_trie[is_s.idx()] = - IsEmptyTreeGadget::construct(&mut cb.base, parent_data.rlc.expr(), &r); + IsEmptyTreeGadget::construct(cb, parent_data.rlc.expr(), &r); // Calculate the key RLC let rlp_key = &mut config.rlp_key[is_s.idx()]; - *rlp_key = ListKeyGadget::construct(&mut cb.base, &key_items[is_s.idx()]); + *rlp_key = ListKeyGadget::construct(cb, &key_items[is_s.idx()]); // Storage root and codehash are always 32-byte hashes. require!(storage_items[is_s.idx()].len() => HASH_WIDTH); @@ -166,7 +167,7 @@ impl AccountLeafConfig { // Key key_rlc[is_s.idx()] = key_data.rlc.expr() + rlp_key.key.expr( - &mut cb.base, + cb, rlp_key.key_value.clone(), key_data.mult.expr(), key_data.is_odd.expr(), @@ -200,10 +201,10 @@ impl AccountLeafConfig { require!(config.rlp_key[is_s.idx()].rlp_list.len() => config.rlp_key[is_s.idx()].key_value.num_bytes() + value_list_num_bytes); // Key done, set the starting values - KeyData::store_defaults(&mut cb.base, &ctx.memory[key_memory(is_s)]); + KeyData::store_defaults(cb, &ctx.memory[key_memory(is_s)]); // Store the new parent ParentData::store( - &mut cb.base, + cb, &ctx.memory[parent_memory(is_s)], storage_rlc[is_s.idx()].expr(), true.expr(), @@ -216,7 +217,7 @@ impl AccountLeafConfig { // TODO(Brecht): For non-existing accounts it should be impossible to prove // storage leaves unless it's also a non-existing proof? MainData::store( - &mut cb.base, + cb, &ctx.memory[main_memory()], [ config.main_data.proof_type.expr(), @@ -323,7 +324,7 @@ impl AccountLeafConfig { }} // Put the data in the lookup table - let (proof_type, value_prev, value) = _matchx! {cb.base, + let (proof_type, value_prev, value) = _matchx! {cb, config.is_nonce_mod => (MPTProofType::NonceChanged.expr(), nonce_rlc[true.idx()].expr(), nonce_rlc[false.idx()].expr()), config.is_balance_mod => (MPTProofType::BalanceChanged.expr(), balance_rlc[true.idx()].expr(), balance_rlc[false.idx()].expr()), config.is_storage_mod => (MPTProofType::StorageChanged.expr(), storage_rlc[true.idx()].expr(), storage_rlc[false.idx()].expr()), @@ -357,9 +358,9 @@ impl AccountLeafConfig { config } - pub fn assign>( + pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, ctx: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/branch.rs b/zkevm-circuits/src/mpt_circuit/branch.rs index 96a579fec1..439c5cdc91 100644 --- a/zkevm-circuits/src/mpt_circuit/branch.rs +++ b/zkevm-circuits/src/mpt_circuit/branch.rs @@ -13,7 +13,7 @@ use super::{ }; use crate::{ circuit, - circuit_tools::{cell_manager::Cell, constraint_builder::RLCChainable, gadgets::LtGadget, cached_region::{CachedRegion, ChallengeSet}}, + circuit_tools::{cell_manager::{Cell, EvmCellType}, constraint_builder::RLCChainable, gadgets::LtGadget, cached_region::{CachedRegion, ChallengeSet}}, mpt_circuit::{ helpers::{nibble_rlc, Indexable}, param::{HASH_WIDTH, RLP_NIL}, @@ -61,17 +61,17 @@ impl BranchGadget { let mut config = BranchGadget::default(); - circuit!([meta, cb.base], { + circuit!([meta, cb], { // Data let children: [RLPItemView; ARITY + 1] = - array_init::array_init(|i| ctx.rlp_item(meta, &mut cb.base, i)); + array_init::array_init(|i| ctx.rlp_item(meta, cb, i)); let mut num_bytes_left = vec![0.expr(); 2]; let mut node_rlc = vec![0.expr(); 2]; let mut mult = vec![1.expr(); 2]; for is_s in [true, false] { // Read the list - config.rlp_list[is_s.idx()] = RLPListDataGadget::construct(&mut cb.base); + config.rlp_list[is_s.idx()] = RLPListDataGadget::construct(cb); // Start RLC encoding the RLP data starting with the list RLP bytes (node_rlc[is_s.idx()], mult[is_s.idx()]) = config.rlp_list[is_s.idx()].rlp_list.rlc_rlp_only(&r); @@ -79,7 +79,7 @@ impl BranchGadget { // Keep track of how many bytes the branch contains to make sure it's correct. num_bytes_left[is_s.idx()] = config.rlp_list[is_s.idx()].rlp_list.len(); - config.mod_rlc[is_s.idx()] = cb.base.query_cell(); + config.mod_rlc[is_s.idx()] = cb.query_cell(); // Check if the branch is hashed or not config.is_not_hashed[is_s.idx()] = LtGadget::construct( @@ -202,7 +202,7 @@ impl BranchGadget { // Update the key RLC and multiplier for the branch nibble. let (key_rlc_post_branch, key_mult_post_branch) = nibble_rlc( - &mut cb.base, + cb, key_rlc.expr(), key_mult.expr(), is_key_odd.expr(), @@ -211,7 +211,7 @@ impl BranchGadget { ); // Also calculate the key RLC and multiplier for the drifted nibble. let (key_rlc_post_drifted, key_mult_post_drifted) = nibble_rlc( - &mut cb.base, + cb, key_rlc.expr(), key_mult.expr(), is_key_odd.expr(), @@ -269,9 +269,9 @@ impl BranchGadget { self.post_state.as_ref().unwrap().clone() } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, _mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/extension.rs b/zkevm-circuits/src/mpt_circuit/extension.rs index ac060fe631..d8728a8ae1 100644 --- a/zkevm-circuits/src/mpt_circuit/extension.rs +++ b/zkevm-circuits/src/mpt_circuit/extension.rs @@ -56,20 +56,20 @@ impl ExtensionGadget { let mut config = ExtensionGadget::default(); - circuit!([meta, cb.base], { + circuit!([meta, cb], { // Data let key_items = [ - ctx.rlp_item(meta, &mut cb.base, ExtensionBranchRowType::KeyS as usize), - ctx.nibbles(meta, &mut cb.base, ExtensionBranchRowType::KeyC as usize), + ctx.rlp_item(meta,cb, ExtensionBranchRowType::KeyS as usize), + ctx.nibbles(meta, cb, ExtensionBranchRowType::KeyC as usize), ]; let rlp_value = [ - ctx.rlp_item(meta, &mut cb.base, ExtensionBranchRowType::ValueS as usize), - ctx.rlp_item(meta, &mut cb.base, ExtensionBranchRowType::ValueC as usize), + ctx.rlp_item(meta, cb, ExtensionBranchRowType::ValueS as usize), + ctx.rlp_item(meta, cb, ExtensionBranchRowType::ValueC as usize), ]; - config.rlp_key = ListKeyGadget::construct(&mut cb.base, &key_items[0]); + config.rlp_key = ListKeyGadget::construct(cb, &key_items[0]); // TODO(Brecht): add lookup constraint - config.is_key_part_odd = cb.base.query_cell(); + config.is_key_part_odd = cb.query_cell(); let mut branch_rlp_rlc = vec![0.expr(); 2]; for is_s in [true, false] { @@ -138,7 +138,7 @@ impl ExtensionGadget { // implemented. let key_rlc = key_data.rlc.expr() + ext_key_rlc_expr( - &mut cb.base, + cb, config.rlp_key.key_value.clone(), key_data.mult.expr(), config.is_key_part_odd.expr(), @@ -158,7 +158,7 @@ impl ExtensionGadget { let key_num_bytes_for_mult = key_len - ifx! {not!(key_data.is_odd.expr() * config.is_key_part_odd.expr()) => { 1.expr() }}; // Get the multiplier for this key length - config.mult_key = cb.base.query_cell(); + config.mult_key = cb.query_cell(); require!((FixedTableTag::RMult, key_num_bytes_for_mult, config.mult_key.expr()) => @"fixed"); // Store the post ext state @@ -178,9 +178,9 @@ impl ExtensionGadget { self.post_state.as_ref().unwrap().clone() } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, _mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/extension_branch.rs b/zkevm-circuits/src/mpt_circuit/extension_branch.rs index 1d6fb7189c..e0fa51d945 100644 --- a/zkevm-circuits/src/mpt_circuit/extension_branch.rs +++ b/zkevm-circuits/src/mpt_circuit/extension_branch.rs @@ -14,7 +14,7 @@ use super::{ }; use crate::{ circuit, - circuit_tools::{cell_manager::Cell, cached_region::{CachedRegion, ChallengeSet}}, + circuit_tools::{cell_manager::{Cell, EvmCellType}, cached_region::{CachedRegion, ChallengeSet}}, mpt_circuit::{ helpers::{key_memory, parent_memory, Indexable, KeyData, ParentData}, witness_row::ExtensionBranchRowType, @@ -42,27 +42,27 @@ impl ExtensionBranchConfig { .cell_manager .as_mut() .unwrap() - .reset(ExtensionBranchRowType::Count as usize); + .reset(meta, ExtensionBranchRowType::Count as usize); let mut config = ExtensionBranchConfig::default(); - circuit!([meta, cb.base], { + circuit!([meta, cb], { // General inputs - config.is_extension = cb.base.query_bool(); + config.is_extension = cb.query_bool(); // If we're in a placeholder, both the extension and the branch parts are // placeholders for is_s in [true, false] { - config.is_placeholder[is_s.idx()] = cb.base.query_bool(); + config.is_placeholder[is_s.idx()] = cb.query_bool(); } // Don't allow both branches to be placeholders require!(config.is_placeholder[true.idx()].expr() + config.is_placeholder[false.idx()].expr() => bool); // Load the last key values - config.key_data = KeyData::load(&mut cb.base, &ctx.memory[key_memory(true)], 0.expr()); + config.key_data = KeyData::load(cb, &ctx.memory[key_memory(true)], 0.expr()); // Load the parent values for is_s in [true, false] { config.parent_data[is_s.idx()] = ParentData::load( "branch load", - &mut cb.base, + cb, &ctx.memory[parent_memory(is_s)], 0.expr(), ); @@ -134,7 +134,7 @@ impl ExtensionBranchConfig { for is_s in [true, false] { ifx! {not!(config.is_placeholder[is_s.idx()].expr()) => { KeyData::store( - &mut cb.base, + cb, &ctx.memory[key_memory(is_s)], branch.key_rlc_post_branch.expr(), branch.key_mult_post_branch.expr(), @@ -146,7 +146,7 @@ impl ExtensionBranchConfig { false.expr(), ); ParentData::store( - &mut cb.base, + cb, &ctx.memory[parent_memory(is_s)], branch.mod_rlc[is_s.idx()].expr(), false.expr(), @@ -155,7 +155,7 @@ impl ExtensionBranchConfig { ); } elsex { KeyData::store( - &mut cb.base, + cb, &ctx.memory[key_memory(is_s)], config.key_data.rlc.expr(), config.key_data.mult.expr(), @@ -167,7 +167,7 @@ impl ExtensionBranchConfig { branch.is_key_odd.expr(), ); ParentData::store( - &mut cb.base, + cb, &ctx.memory[parent_memory(is_s)], config.parent_data[is_s.idx()].rlc.expr(), config.parent_data[is_s.idx()].is_root.expr(), @@ -181,9 +181,9 @@ impl ExtensionBranchConfig { config } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index 577a019843..b9f78c54c9 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -1,7 +1,7 @@ use crate::{ assign, circuit, circuit_tools::{ - cell_manager::{Cell, CellManager}, + cell_manager::{Cell, CellManager_, CellTypeTrait, EvmCellType}, constraint_builder::{ ConstraintBuilder, RLCChainable, RLCChainableValue, RLCable, RLCableValue, }, @@ -25,7 +25,6 @@ use super::{ rlp_gadgets::{ get_ext_odd_nibble_value, RLPItemGadget, RLPItemWitness, RLPListGadget, RLPListWitness, }, - table::Table, FixedTableTag, }; @@ -56,10 +55,10 @@ pub(crate) struct LeafKeyWitness { } impl LeafKeyGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, rlp_key: RLPItemView) -> Self { + pub(crate) fn construct(cb: &mut MPTConstraintBuilder, rlp_key: RLPItemView) -> Self { circuit!([meta, cb], { let has_no_nibbles = IsEqualGadget::::construct( - cb, + &mut cb.base, rlp_key.bytes()[0].expr(), KEY_TERMINAL_PREFIX_EVEN.expr(), ); @@ -69,14 +68,14 @@ impl LeafKeyGadget { pub(crate) fn expr( &self, - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, rlp_key: RLPItemView, key_mult_prev: Expression, is_key_odd: Expression, r: &Expression, ) -> Expression { - circuit!([meta, cb], { - let calc_rlc = |cb: &mut ConstraintBuilder, + circuit!([meta, cb.base], { + let calc_rlc = |cb: &mut MPTConstraintBuilder, bytes: &[Expression], is_key_odd: Expression| { leaf_key_rlc(cb, bytes, key_mult_prev.expr(), is_key_odd.expr(), r) @@ -96,9 +95,9 @@ impl LeafKeyGadget { }) } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, bytes: &[u8], ) -> Result { @@ -143,7 +142,7 @@ impl LeafKeyWitness { } pub(crate) fn ext_key_rlc_expr( - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, key_value: RLPItemView, key_mult_prev: Expression, is_key_part_odd: Expression, @@ -151,10 +150,10 @@ pub(crate) fn ext_key_rlc_expr( data: [Vec>; 2], r: &Expression, ) -> Expression { - circuit!([meta, cb], { + circuit!([meta, cb.base], { let (is_short, is_long) = (key_value.is_short(), key_value.is_long()); let mult_first_odd = ifx! {is_key_odd => { 1.expr() } elsex { 16.expr() }}; - let calc_rlc = |cb: &mut ConstraintBuilder, + let calc_rlc = |cb: &mut MPTConstraintBuilder, bytes: &[Expression], key_mult_first_even: Expression| { ext_key_rlc( @@ -256,7 +255,7 @@ pub(crate) struct ListKeyWitness { } impl ListKeyGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, key_value: &RLPItemView) -> Self { + pub(crate) fn construct(cb: &mut MPTConstraintBuilder, key_value: &RLPItemView) -> Self { let rlp_list_bytes = cb.query_bytes(); let rlp_list_bytes_expr = rlp_list_bytes.iter().map(|c| c.expr()).collect::>(); let key = LeafKeyGadget::construct(cb, key_value.clone()); @@ -268,9 +267,9 @@ impl ListKeyGadget { } } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, list_bytes: &[u8], key_item: &RLPItemWitness, @@ -330,7 +329,7 @@ pub(crate) struct KeyDataWitness { impl KeyData { pub(crate) fn load( - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, memory: &MemoryBank, offset: Expression, ) -> Self { @@ -344,10 +343,10 @@ impl KeyData { drifted_num_nibbles: cb.query_cell(), drifted_is_odd: cb.query_cell(), }; - circuit!([meta, cb], { + circuit!([meta, cb.base], { memory.load( "key load", - cb, + &mut cb.base, offset, &[ key_data.rlc.expr(), @@ -365,7 +364,7 @@ impl KeyData { } pub(crate) fn store( - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, memory: &MemoryBank, rlc: Expression, mult: Expression, @@ -377,7 +376,7 @@ impl KeyData { drifted_is_odd: Expression, ) { memory.store( - cb, + &mut cb.base, &[ rlc, mult, @@ -391,8 +390,8 @@ impl KeyData { ); } - pub(crate) fn store_defaults(cb: &mut ConstraintBuilder, memory: &MemoryBank) { - memory.store(cb, &KeyData::default_values_expr()); + pub(crate) fn store_defaults(cb: &mut MPTConstraintBuilder, memory: &MemoryBank) { + memory.store(&mut cb.base, &KeyData::default_values_expr()); } pub(crate) fn default_values_expr() -> [Expression; 8] { @@ -408,8 +407,8 @@ impl KeyData { ] } - pub(crate) fn witness_store>( - _region: &mut CachedRegion<'_, '_, F, C>, + pub(crate) fn witness_store>( + _region: &mut CachedRegion<'_, '_, F, S>, offset: usize, memory: &mut MemoryBank, rlc: F, @@ -434,9 +433,9 @@ impl KeyData { Ok(()) } - pub(crate) fn witness_load>( + pub(crate) fn witness_load>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, memory: &MemoryBank, load_offset: usize, @@ -484,7 +483,7 @@ pub(crate) struct ParentDataWitness { impl ParentData { pub(crate) fn load( description: &'static str, - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, memory: &MemoryBank, offset: Expression, ) -> Self { @@ -494,10 +493,10 @@ impl ParentData { is_placeholder: cb.query_cell(), drifted_parent_rlc: cb.query_cell(), }; - circuit!([meta, cb], { + circuit!([meta, cb.base], { memory.load( description, - cb, + &mut cb.base, offset, &[ parent_data.rlc.expr(), @@ -511,18 +510,18 @@ impl ParentData { } pub(crate) fn store( - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, memory: &MemoryBank, rlc: Expression, is_root: Expression, is_placeholder: Expression, drifted_parent_rlc: Expression, ) { - memory.store(cb, &[rlc, is_root, is_placeholder, drifted_parent_rlc]); + memory.store(&mut cb.base, &[rlc, is_root, is_placeholder, drifted_parent_rlc]); } - pub(crate) fn witness_store>( - _region: &mut CachedRegion<'_, '_, F, C>, + pub(crate) fn witness_store>( + _region: &mut CachedRegion<'_, '_, F, S>, offset: usize, memory: &mut MemoryBank, rlc: F, @@ -542,9 +541,9 @@ impl ParentData { Ok(()) } - pub(crate) fn witness_load>( + pub(crate) fn witness_load>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, memory: &MemoryBank, load_offset: usize, @@ -586,7 +585,7 @@ pub(crate) struct MainDataWitness { impl MainData { pub(crate) fn load( description: &'static str, - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, memory: &MemoryBank, offset: Expression, ) -> Self { @@ -597,10 +596,10 @@ impl MainData { root_prev: cb.query_cell(), root: cb.query_cell(), }; - circuit!([meta, cb], { + circuit!([meta, cb.base], { memory.load( description, - cb, + &mut cb.base, offset, &[ main_data.proof_type.expr(), @@ -615,15 +614,15 @@ impl MainData { } pub(crate) fn store( - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, memory: &MemoryBank, values: [Expression; 5], ) { - memory.store(cb, &values); + memory.store(&mut cb.base, &values); } - pub(crate) fn witness_store>( - _region: &mut CachedRegion<'_, '_, F, C>, + pub(crate) fn witness_store>( + _region: &mut CachedRegion<'_, '_, F, S>, offset: usize, memory: &mut MemoryBank, proof_type: usize, @@ -644,9 +643,9 @@ impl MainData { Ok(()) } - pub(crate) fn witness_load>( + pub(crate) fn witness_load>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, memory: &MemoryBank, load_offset: usize, @@ -671,14 +670,14 @@ impl MainData { /// Add the nibble from the drifted branch pub(crate) fn nibble_rlc( - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, key_rlc: Expression, key_mult_prev: Expression, is_key_odd: Expression, nibble: Expression, r: &Expression, ) -> (Expression, Expression) { - circuit!([meta, cb], { + circuit!([meta, cb.base], { let (nibble_mult, mult) = ifx! {is_key_odd => { // The nibble will be added as the least significant nibble, the multiplier needs to advance (1.expr(), r.expr()) @@ -694,13 +693,13 @@ pub(crate) fn nibble_rlc( } pub(crate) fn leaf_key_rlc( - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, bytes: &[Expression], key_mult_prev: Expression, is_key_odd: Expression, r: &Expression, ) -> Expression { - circuit!([meta, cb], { + circuit!([meta, cb.base], { // Add the odd nibble first if we have one. let (rlc, mult) = ifx! {is_key_odd => { (get_terminal_odd_nibble(bytes[0].expr()) * key_mult_prev.expr(), r.expr()) @@ -713,7 +712,7 @@ pub(crate) fn leaf_key_rlc( } pub(crate) fn ext_key_rlc( - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, bytes: &[Expression], key_mult_prev: Expression, is_odd: Expression, @@ -721,7 +720,7 @@ pub(crate) fn ext_key_rlc( key_mult_first_odd: Expression, r: &Expression, ) -> Expression { - circuit!([meta, cb], { + circuit!([meta, cb.base], { // Add the odd nibble first if we have one. let (rlc, mult) = ifx! {is_odd => { (get_ext_odd_nibble(bytes[0].expr()) * key_mult_prev.expr() * rlc_mult_first_odd, key_mult_first_odd.expr()) @@ -757,7 +756,11 @@ pub(crate) fn ext_key_rlc_value( // Returns the number of nibbles stored in a key value pub(crate) mod num_nibbles { - use crate::{circuit, circuit_tools::{constraint_builder::ConstraintBuilder}, mpt_circuit::table::Table}; + use crate::{ + circuit, + circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::EvmCellType}, + mpt_circuit::helpers::MPTConstraintBuilder, + }; use eth_types::Field; use halo2_proofs::plonk::Expression; @@ -765,8 +768,8 @@ pub(crate) mod num_nibbles { key_len: Expression, is_key_odd: Expression, ) -> Expression { - let mut cb = ConstraintBuilder::::new(0, None); - circuit!([meta, cb], { + let mut cb = MPTConstraintBuilder::::new(0, None); + circuit!([meta, cb.base], { ifx! {is_key_odd => { key_len.expr() * 2.expr() - 1.expr() } elsex { @@ -798,15 +801,86 @@ pub(crate) fn main_memory() -> String { /// MPTConstraintBuilder #[derive(Clone)] pub struct MPTConstraintBuilder { - pub base: ConstraintBuilder, + pub base: ConstraintBuilder, } impl MPTConstraintBuilder { - pub(crate) fn new(max_degree: usize, cell_manager: Option>) -> Self { + + pub(crate) fn new(max_degree: usize, cell_manager: Option>) -> Self { MPTConstraintBuilder { base: ConstraintBuilder::new(max_degree, cell_manager), } } + + pub(crate) fn query_bool(&mut self) -> Cell { + self.base.query_bool() + } + + pub(crate) fn query_byte(&mut self) -> Cell { + // TODO(Brecht): fix + self.base.query_one(EvmCellType::StoragePhase1) + } + + pub(crate) fn query_bytes(&mut self) -> [Cell; N] { + self.base.query_cells_dyn(EvmCellType::StoragePhase1, N) + .try_into() + .unwrap() + } + + pub(crate) fn query_bytes_dyn(&mut self, count: usize) -> Vec> { + self.base.query_cells_dyn(EvmCellType::StoragePhase1, count) + } + + pub(crate) fn query_cell(&mut self) -> Cell { + self.base.query_default() + } + + pub(crate) fn query_cells(&mut self) -> [Cell; N] { + self.base.query_cells_dyn(EvmCellType::default(), N) + .try_into() + .unwrap() + } + + // Pass through to base + pub(crate) fn require_equal( + &mut self, + name: &'static str, + lhs: Expression, + rhs: Expression, + ) { + self.base.require_equal(name, lhs, rhs) + } + + pub(crate) fn require_in_set( + &mut self, + name: &'static str, + value: Expression, + set: Vec>, + ) { + self.base.require_in_set(name, value, set) + } + + pub(crate) fn require_boolean(&mut self, name: &'static str, value: Expression) { + self.base.require_boolean(name, value) + } + + pub(crate) fn lookup>( + &mut self, + description: &'static str, + tag: S, + values: Vec> + ) { + self.base.lookup(description, tag, values) + } + + pub(crate) fn push_condition(&mut self, condition: Expression) { + self.base.push_condition(condition) + } + + pub(crate) fn pop_condition(&mut self) { + self.base.pop_condition() + } + } /// Returns `1` when `value == 0`, and returns `0` otherwise. @@ -818,19 +892,19 @@ pub struct IsEmptyTreeGadget { impl IsEmptyTreeGadget { pub(crate) fn construct( - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, parent_rlc: Expression, r: &Expression, ) -> Self { - circuit!([meta, cb], { + circuit!([meta, cb.base], { let empty_root_rlc = EMPTY_TRIE_HASH .iter() .map(|v| v.expr()) .collect::>() .rlc(r); let is_in_empty_trie = - IsEqualGadget::construct(cb, parent_rlc.expr(), empty_root_rlc.expr()); - let is_in_empty_branch = IsEqualGadget::construct(cb, parent_rlc.expr(), 0.expr()); + IsEqualGadget::construct(&mut cb.base, parent_rlc.expr(), empty_root_rlc.expr()); + let is_in_empty_branch = IsEqualGadget::construct(&mut cb.base, parent_rlc.expr(), 0.expr()); Self { is_in_empty_trie, @@ -843,9 +917,9 @@ impl IsEmptyTreeGadget { or::expr(&[self.is_in_empty_trie.expr(), self.is_in_empty_branch.expr()]) } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, parent_rlc: F, r: F, @@ -877,7 +951,7 @@ impl DriftedGadget { let mut config = DriftedGadget::default(); circuit!([meta, cb.base], { ifx! {parent_data[true.idx()].is_placeholder.expr() + parent_data[false.idx()].is_placeholder.expr() => { - config.drifted_rlp_key = ListKeyGadget::construct(&mut cb.base, drifted_item); + config.drifted_rlp_key = ListKeyGadget::construct(cb, drifted_item); for is_s in [true, false] { ifx! {parent_data[is_s.idx()].is_placeholder.expr() => { // Check that the drifted leaf is unchanged and is stored at `drifted_index`. @@ -892,7 +966,7 @@ impl DriftedGadget { key_data[is_s.idx()].drifted_is_odd.expr(), ); let key_rlc = key_rlc.expr() + config.drifted_rlp_key.key.expr( - &mut cb.base, + cb, config.drifted_rlp_key.key_value.clone(), key_mult.expr(), is_key_odd.expr(), @@ -920,9 +994,9 @@ impl DriftedGadget { }) } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, parent_data: &[ParentDataWitness], drifted_list_bytes: &[u8], @@ -963,9 +1037,9 @@ impl WrongGadget { // Get the previous key data ifx! {is_non_existing, not!(is_in_empty_tree) => { // Calculate the key - config.wrong_rlp_key = ListKeyGadget::construct(&mut cb.base, wrong_item); + config.wrong_rlp_key = ListKeyGadget::construct(cb, wrong_item); let key_rlc_wrong = key_data.rlc.expr() + config.wrong_rlp_key.key.expr( - &mut cb.base, + cb, config.wrong_rlp_key.key_value.clone(), key_data.mult.expr(), key_data.is_odd.expr(), @@ -988,9 +1062,9 @@ impl WrongGadget { }) } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, is_non_existing: bool, key_rlc: &[F], @@ -1040,10 +1114,10 @@ pub struct MainRLPGadget { impl MainRLPGadget { pub(crate) fn construct(cb: &mut MPTConstraintBuilder, r: &Expression) -> Self { let mut config = MainRLPGadget::default(); - config.bytes = cb.base.query_cells::<34>().to_vec(); - circuit!([meta, cb.base], { + config.bytes = cb.query_cells::<34>().to_vec(); + circuit!([meta, cb], { config.rlp = RLPItemGadget::construct( - &mut cb.base, + cb, &config .bytes .iter() @@ -1051,20 +1125,20 @@ impl MainRLPGadget { .collect::>(), ); - config.num_bytes = cb.base.query_cell(); + config.num_bytes = cb.query_cell(); require!(config.num_bytes => config.rlp.num_bytes()); - config.len = cb.base.query_cell(); + config.len = cb.query_cell(); require!(config.len => config.rlp.len()); - config.rlc_content = cb.base.query_cell(); + config.rlc_content = cb.query_cell(); require!(config.rlc_content => config.rlp.rlc_content(r)); - config.rlc_rlp = cb.base.query_cell(); - require!(config.rlc_rlp => config.rlp.rlc_rlp(&mut cb.base, r)); - config.mult_diff = cb.base.query_cell(); + config.rlc_rlp = cb.query_cell(); + require!(config.rlc_rlp => config.rlp.rlc_rlp(cb, r)); + config.mult_diff = cb.query_cell(); let mult_diff = config.mult_diff.expr(); require!((FixedTableTag::RMult, config.rlp.num_bytes(), mult_diff) => @format!("fixed")); // "free" input that needs to be constrained externally! - config.tag = cb.base.query_cell(); + config.tag = cb.query_cell(); // Range/zero checks // These range checks ensure that the value in the RLP columns are all byte @@ -1079,9 +1153,9 @@ impl MainRLPGadget { }) } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, bytes: &[u8], r: F, @@ -1117,11 +1191,11 @@ impl MainRLPGadget { pub(crate) fn create_view( &self, meta: &mut VirtualCells, - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, rot: usize, is_nibbles: bool, ) -> RLPItemView { - circuit!([meta, cb], { + circuit!([meta, cb.base], { require!(self.tag.rot(meta, rot) => self.tag(is_nibbles).expr()); }); RLPItemView { diff --git a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs index 7559acdbd5..8eadab8e70 100644 --- a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs +++ b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs @@ -3,12 +3,11 @@ use crate::{ circuit, circuit_tools::{ - cell_manager::{Cell}, + cell_manager::{Cell, EvmCellType}, constraint_builder::{ConstraintBuilder, RLCable, RLCableValue}, cached_region::{CachedRegion, ChallengeSet}, }, matchw, mpt_circuit::param::{RLP_LIST_LONG, RLP_LIST_SHORT, RLP_SHORT}, - mpt_circuit::table::Table, util::Expr, }; use eth_types::Field; @@ -17,7 +16,7 @@ use halo2_proofs::{ plonk::{Error, Expression}, }; -use super::param::{KEY_PREFIX_ODD, KEY_TERMINAL_PREFIX_ODD, RLP_LONG}; +use super::{param::{KEY_PREFIX_ODD, KEY_TERMINAL_PREFIX_ODD, RLP_LONG}, helpers::MPTConstraintBuilder}; #[derive(Clone, Debug, Default)] pub(crate) struct RLPListGadget { @@ -38,7 +37,7 @@ pub(crate) struct RLPListWitness { } impl RLPListGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, bytes: &[Expression]) -> Self { + pub(crate) fn construct(cb: &mut MPTConstraintBuilder, bytes: &[Expression]) -> Self { // TODO(Brecht): add lookup RLPListGadget { is_short: cb.query_cell(), @@ -49,9 +48,9 @@ impl RLPListGadget { } } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, bytes: &[u8], ) -> Result { @@ -106,7 +105,7 @@ impl RLPListGadget { /// Number of RLP bytes pub(crate) fn num_rlp_bytes(&self) -> Expression { - let mut cb = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.is_short() => 1.expr(), @@ -123,7 +122,7 @@ impl RLPListGadget { /// Returns the length of the list (excluding RLP bytes) pub(crate) fn len(&self) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.is_short() => get_len_list_short::expr(self.bytes[0].expr()), @@ -140,7 +139,7 @@ impl RLPListGadget { /// Returns the rlc of only the RLP bytes pub(crate) fn rlc_rlp_only(&self, r: &Expression) -> (Expression, Expression) { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.is_short() => (self.bytes[..1].rlc(r), pow::expr(r.expr(), 1)), @@ -224,8 +223,8 @@ pub(crate) struct RLPListDataGadget { } impl RLPListDataGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder) -> Self { - let rlp_list_bytes = cb.query_bytes(); + pub(crate) fn construct(cb: &mut MPTConstraintBuilder) -> Self { + let rlp_list_bytes = cb.query_bytes::<3>(); let rlp_list_bytes_expr = rlp_list_bytes.iter().map(|c| c.expr()).collect::>(); RLPListDataGadget { rlp_list: RLPListGadget::construct(cb, &rlp_list_bytes_expr), @@ -233,9 +232,9 @@ impl RLPListDataGadget { } } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, list_bytes: &[u8], ) -> Result { @@ -269,7 +268,7 @@ pub(crate) struct RLPValueWitness { } impl RLPValueGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, bytes: &[Expression]) -> Self { + pub(crate) fn construct(cb: &mut MPTConstraintBuilder, bytes: &[Expression]) -> Self { // TODO(Brecht): add lookup RLPValueGadget { is_short: cb.query_cell(), @@ -280,9 +279,9 @@ impl RLPValueGadget { } } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, bytes: &[u8], ) -> Result { @@ -339,7 +338,7 @@ impl RLPValueGadget { /// Number of RLP bytes pub(crate) fn num_rlp_bytes(&self) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.is_short() => 0.expr(), @@ -351,7 +350,7 @@ impl RLPValueGadget { /// Number of bytes in total (including RLP bytes) pub(crate) fn num_bytes(&self) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.is_short() => 1.expr(), @@ -366,7 +365,7 @@ impl RLPValueGadget { /// Length of the value (excluding RLP bytes) pub(crate) fn len(&self) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.is_short() => 1.expr(), @@ -389,7 +388,7 @@ impl RLPValueGadget { } pub(crate) fn rlc_value(&self, r: &Expression) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.is_short() => { @@ -567,16 +566,16 @@ pub(crate) struct RLPItemWitness { } impl RLPItemGadget { - pub(crate) fn construct(cb: &mut ConstraintBuilder, bytes: &[Expression]) -> Self { + pub(crate) fn construct(cb: &mut MPTConstraintBuilder, bytes: &[Expression]) -> Self { RLPItemGadget { value: RLPValueGadget::construct(cb, bytes), list: RLPListGadget::construct(cb, bytes), } } - pub(crate) fn assign>( + pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, bytes: &[u8], ) -> Result { @@ -593,7 +592,7 @@ impl RLPItemGadget { // Single RLP byte containing the byte value pub(crate) fn is_short(&self) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.is_short(), @@ -604,7 +603,7 @@ impl RLPItemGadget { // Single RLP byte containing the length of the value pub(crate) fn is_long(&self) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.is_long(), @@ -616,7 +615,7 @@ impl RLPItemGadget { // RLP byte containing the lenght of the length, // followed by the length, followed by the actual data pub(crate) fn is_very_long(&self) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.is_very_long(), @@ -627,7 +626,7 @@ impl RLPItemGadget { /// Number of RLP bytes pub(crate) fn num_rlp_bytes(&self) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.num_rlp_bytes(), @@ -638,7 +637,7 @@ impl RLPItemGadget { /// Number of bytes in total (including RLP bytes) pub(crate) fn num_bytes(&self) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.num_bytes(), @@ -649,7 +648,7 @@ impl RLPItemGadget { /// Length of the value (excluding RLP bytes) pub(crate) fn len(&self) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.len(), @@ -660,7 +659,7 @@ impl RLPItemGadget { pub(crate) fn rlc_rlp( &self, - cb: &mut ConstraintBuilder, + cb: &mut MPTConstraintBuilder, r: &Expression, ) -> Expression { circuit!([meta, cb], { @@ -674,7 +673,7 @@ impl RLPItemGadget { // Returns the RLC of the value if the RLP is a string, // returns the RLC of the full string if the RLP is a list. pub(crate) fn rlc_content(&self, r: &Expression) -> Expression { - let mut cb: ConstraintBuilder = ConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.rlc_value(r), diff --git a/zkevm-circuits/src/mpt_circuit/start.rs b/zkevm-circuits/src/mpt_circuit/start.rs index eb4b38778b..863a582dd2 100644 --- a/zkevm-circuits/src/mpt_circuit/start.rs +++ b/zkevm-circuits/src/mpt_circuit/start.rs @@ -6,7 +6,7 @@ use super::{ use crate::{ circuit, circuit_tools::{ - cell_manager::Cell, cached_region::{CachedRegion, ChallengeSet}, + cell_manager::{Cell, EvmCellType}, cached_region::{CachedRegion, ChallengeSet}, }, mpt_circuit::{ helpers::{ @@ -37,16 +37,16 @@ impl StartConfig { .cell_manager .as_mut() .unwrap() - .reset(StartRowType::Count as usize); + .reset(meta, StartRowType::Count as usize); let mut config = StartConfig::default(); - circuit!([meta, cb.base], { + circuit!([meta, cb], { let root_items = [ - ctx.rlp_item(meta, &mut cb.base, StartRowType::RootS as usize), - ctx.rlp_item(meta, &mut cb.base, StartRowType::RootC as usize), + ctx.rlp_item(meta, cb, StartRowType::RootS as usize), + ctx.rlp_item(meta, cb, StartRowType::RootC as usize), ]; - config.proof_type = cb.base.query_cell(); + config.proof_type = cb.query_cell(); let mut root = vec![0.expr(); 2]; for is_s in [true, false] { @@ -54,7 +54,7 @@ impl StartConfig { } MainData::store( - &mut cb.base, + cb, &ctx.memory[main_memory()], [ config.proof_type.expr(), @@ -67,23 +67,23 @@ impl StartConfig { for is_s in [true, false] { ParentData::store( - &mut cb.base, + cb, &ctx.memory[parent_memory(is_s)], root[is_s.idx()].expr(), true.expr(), false.expr(), root[is_s.idx()].expr(), ); - KeyData::store_defaults(&mut cb.base, &ctx.memory[key_memory(is_s)]); + KeyData::store_defaults(cb, &ctx.memory[key_memory(is_s)]); } }); config } - pub fn assign>( + pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, _ctx: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs index cdf05cb4b5..b9b407d7f2 100644 --- a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs @@ -9,7 +9,7 @@ use halo2_proofs::{ use crate::{ circuit, circuit_tools::{ - cell_manager::Cell, + cell_manager::{Cell, EvmCellType}, constraint_builder::RLCChainable, gadgets::{IsEqualGadget, LtGadget}, cached_region::{CachedRegion, ChallengeSet}, }, @@ -60,25 +60,25 @@ impl StorageLeafConfig { .cell_manager .as_mut() .unwrap() - .reset(StorageRowType::Count as usize); + .reset(meta, StorageRowType::Count as usize); let mut config = StorageLeafConfig::default(); circuit!([meta, cb.base], { let key_items = [ - ctx.rlp_item(meta, &mut cb.base, StorageRowType::KeyS as usize), - ctx.rlp_item(meta, &mut cb.base, StorageRowType::KeyC as usize), + ctx.rlp_item(meta, cb, StorageRowType::KeyS as usize), + ctx.rlp_item(meta, cb, StorageRowType::KeyC as usize), ]; config.value_rlp_bytes = [cb.base.query_bytes(), cb.base.query_bytes()]; let value_item = [ - ctx.rlp_item(meta, &mut cb.base, StorageRowType::ValueS as usize), - ctx.rlp_item(meta, &mut cb.base, StorageRowType::ValueC as usize), + ctx.rlp_item(meta, cb, StorageRowType::ValueS as usize), + ctx.rlp_item(meta, cb, StorageRowType::ValueC as usize), ]; - let drifted_item = ctx.rlp_item(meta, &mut cb.base, StorageRowType::Drifted as usize); - let wrong_item = ctx.rlp_item(meta, &mut cb.base, StorageRowType::Wrong as usize); + let drifted_item = ctx.rlp_item(meta, cb, StorageRowType::Drifted as usize); + let wrong_item = ctx.rlp_item(meta, cb, StorageRowType::Wrong as usize); config.main_data = MainData::load( "main storage", - &mut cb.base, + cb, &ctx.memory[main_memory()], 0.expr(), ); @@ -94,23 +94,23 @@ impl StorageLeafConfig { let parent_data = &mut config.parent_data[is_s.idx()]; *parent_data = ParentData::load( "leaf load", - &mut cb.base, + cb, &ctx.memory[parent_memory(is_s)], 0.expr(), ); // Key data let key_data = &mut config.key_data[is_s.idx()]; - *key_data = KeyData::load(&mut cb.base, &ctx.memory[key_memory(is_s)], 0.expr()); + *key_data = KeyData::load(cb, &ctx.memory[key_memory(is_s)], 0.expr()); // Placeholder leaf checks config.is_in_empty_trie[is_s.idx()] = - IsEmptyTreeGadget::construct(&mut cb.base, parent_data.rlc.expr(), &r); + IsEmptyTreeGadget::construct(cb, parent_data.rlc.expr(), &r); let is_placeholder_leaf = config.is_in_empty_trie[is_s.idx()].expr(); let rlp_key = &mut config.rlp_key[is_s.idx()]; - *rlp_key = ListKeyGadget::construct(&mut cb.base, &key_items[is_s.idx()]); + *rlp_key = ListKeyGadget::construct(cb, &key_items[is_s.idx()]); config.rlp_value[is_s.idx()] = RLPValueGadget::construct( - &mut cb.base, + cb, &config.value_rlp_bytes[is_s.idx()] .iter() .map(|c| c.expr()) @@ -142,7 +142,7 @@ impl StorageLeafConfig { // Key key_rlc[is_s.idx()] = key_data.rlc.expr() + rlp_key.key.expr( - &mut cb.base, + cb, rlp_key.key_value.clone(), key_data.mult.expr(), key_data.is_odd.expr(), @@ -176,10 +176,10 @@ impl StorageLeafConfig { }} // Key done, set the default values - KeyData::store_defaults(&mut cb.base, &ctx.memory[key_memory(is_s)]); + KeyData::store_defaults(cb, &ctx.memory[key_memory(is_s)]); // Store the new parent ParentData::store( - &mut cb.base, + cb, &ctx.memory[parent_memory(is_s)], 0.expr(), true.expr(), @@ -257,9 +257,9 @@ impl StorageLeafConfig { config } - pub fn assign>( + pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, ctx: &MPTConfig, pv: &mut MPTState, offset: usize, diff --git a/zkevm-circuits/src/mpt_circuit/table.rs b/zkevm-circuits/src/mpt_circuit/table.rs index ba1bb8a071..9c9bcb4822 100644 --- a/zkevm-circuits/src/mpt_circuit/table.rs +++ b/zkevm-circuits/src/mpt_circuit/table.rs @@ -3,29 +3,21 @@ use eth_types::Field; use halo2_proofs::{plonk::{Column, Any}, circuit::Value}; use strum_macros::EnumIter; use crate::{ - circuit_tools::cell_manager::TableType, - circuit_tools::{table::LookupTable, cached_region::ChallengeSet}, - table::KeccakTable + circuit_tools::cell_manager::CellTypeTrait, + circuit_tools::{table::LookupTable_, cached_region::ChallengeSet, cell_manager::EvmCellType}, + table::KeccakTable, evm_circuit::table::Table }; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, EnumIter)] -pub enum Table { - Fixed, - Tx, - Rw, - Bytecode, - Block, - Copy, - Keccak, - Exp, -} - -impl TableType for Table {} -impl LookupTable for KeccakTable { +impl LookupTable_ for KeccakTable { + type TableCellType = EvmCellType; - fn get_type(&self) -> Table { - Table::Keccak + fn get_type_(&self) -> EvmCellType { + EvmCellType::Lookup(Table::Keccak) + } + + fn phase(&self) -> u8 { + 0 } fn columns(&self) -> Vec> { diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index ecf71d16c3..773bb6e78c 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -2,7 +2,7 @@ use crate::{ circuit, - circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::TableType, cached_region::{CachedRegion, ChallengeSet}}, + circuit_tools::{constraint_builder::ConstraintBuilder, cell_manager::CellTypeTrait, cached_region::{CachedRegion, ChallengeSet}}, copy_circuit::number_or_hash_to_field, evm_circuit::util::rlc, exp_circuit::{OFFSET_INCREMENT, ROWS_PER_STEP}, @@ -657,10 +657,10 @@ impl MptTable { } } - pub(crate) fn constrain( + pub(crate) fn constrain( &self, meta: &mut VirtualCells<'_, F>, - cb: &mut ConstraintBuilder, + cb: &mut ConstraintBuilder, address_rlc: Expression, proof_type: Expression, key_rlc: Expression, @@ -695,9 +695,9 @@ impl MptTable { Ok(()) } - pub(crate) fn assign_cached>( + pub(crate) fn assign_cached>( &self, - region: &mut CachedRegion<'_, '_, F, C>, + region: &mut CachedRegion<'_, '_, F, S>, offset: usize, row: &MptUpdateRow>, ) -> Result<(), Error> { From c498841d21bd8b92203cd2410a88cfb9ba175e4d Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Tue, 23 May 2023 16:48:05 +0800 Subject: [PATCH 054/102] Fix best_index for CM cell query --- .../src/circuit_tools/cell_manager.rs | 67 ++++++++++++------- zkevm-circuits/src/mpt_circuit.rs | 43 ++++++------ 2 files changed, 64 insertions(+), 46 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index 0164219bcd..7c3c992c64 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -146,15 +146,15 @@ impl From<(C, usize, u8, bool)> for CellConfig { impl CellConfig { pub fn init_columns(&self, meta: &mut ConstraintSystem) -> Vec>{ let mut columns = Vec::with_capacity(self.num_columns); - let _ = columns.iter_mut() - .map(|c| - match self.phase { - 0 => *c = meta.advice_column_in(FirstPhase), - 1 => *c = meta.advice_column_in(SecondPhase), - 2 => *c = meta.advice_column_in(ThirdPhase), - _ => unreachable!(), - } - ); + for _ in 0..self.num_columns { + let tmp = match self.phase { + 0 => meta.advice_column_in(FirstPhase), + 1 => meta.advice_column_in(SecondPhase), + 2 => meta.advice_column_in(ThirdPhase), + _ => unreachable!(), + }; + columns.push(tmp); + } if self.is_permute { let _ = columns.iter().map(|c| meta.enable_equality(c.clone())).collect::>(); } @@ -225,7 +225,6 @@ impl CellManager_ { .for_each(|c| { let cols = c.init_columns(meta); let mut cell_list = Vec::with_capacity(cols.len() * max_height); - let start_width = total_width; query_expression(meta, |meta| { for w in 0..cols.len() { for h in 0..max_height { @@ -236,14 +235,17 @@ impl CellManager_ { index: w, cell_type: c.cell_type, height: 0, - expr: cell_list[cols.len()-1].expr().clone(), + expr: cell_list[cell_list.len()-1].expr().clone(), }); - total_width += 1; } }); - cells.insert(c.cell_type, (start_width, cell_list)); + cells.insert(c.cell_type, (total_width, cell_list)); + total_width += cols.len(); }); + println!("______________\n"); + cells.keys().for_each(|k| println!("cell type: {:?}, start_width: {:?}, #cells: {:?}\n", + k, cells.get(k).unwrap().0, cells.get(k).unwrap().1)); Self { cells, cell_configs, @@ -320,19 +322,15 @@ impl CellManager_ { let (start_width, cell_list) = self.cells.get(&cell_type).expect("Cell type not found"); let window = self.get_config(cell_type).num_columns; + + println!("cell_type {:?} get {:?}", cell_type, start_width); + println!("{:?}", self.cell_configs); + + while targets.len() < count { - // Iterate the window of columns designated for this CellType - // No need to find the best height because cells should be return in order - self.columns[*start_width..start_width + window] - .iter_mut() - .enumerate() - .for_each(|(i, c)| { - assert!(c.cell_type == cell_type); - if c.height < self.max_height { - targets.push(cell_list[i + c.height].clone()); - c.height += 1; - } - }); + // Search best cell in window of columns designated for this CellType + let c = self.next_column(cell_type, &self.columns[*start_width..start_width + window]); + targets.push(cell_list[c.index * self.max_height + c.height].clone()); } targets } @@ -340,5 +338,24 @@ impl CellManager_ { pub(crate) fn query_cell(&mut self, cell_type: C) -> Cell { self.query_cells(cell_type, 1)[0].clone() } + + fn next_column(&self, cell_type: C, columns: &[CellColumn_]) -> CellColumn_ { + let mut best_col: Option> = None; + let mut best_height = self.max_height; + for column in columns.iter() { + assert!(column.cell_type == cell_type); + if column.height < best_height { + best_col = Some(column.clone()); + best_height = column.height; + } + } + match best_col { + Some(col) => col, + // If we reach this case, it means that all the columns of cell_type have assignments + // taking self.height rows, so there's no more space. + None => panic!("not enough cells for query: {:?}", cell_type), + } + } + } diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index c500b87751..2fbaf8f0f7 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -220,9 +220,8 @@ impl MPTConfig { (EvmCellType::StoragePhase2, 10, 1, false), (EvmCellType::LookupByte, 32, 0, false), ], - vec![ - &keccak_table, &fixed_table - ], + // no need to pass in fixed table since it's StoragePhase1 + vec![&keccak_table], 0, 32 ); @@ -686,24 +685,24 @@ mod tests { fn graph_mpt() { use plotters::prelude::*; - let path = "src/mpt_circuit/tests"; - let files = fs::read_dir(path).unwrap(); - let files: Vec = files - .filter_map(Result::ok) - .filter(|d| { - if let Some(e) = d.path().extension() { - e == "json" - } else { - false - } - }).collect(); - - let path = &files[0].path(); - let mut parts = path.to_str().unwrap().split('-'); - parts.next(); - let file = std::fs::File::open(path.clone()); - let reader = std::io::BufReader::new(file.unwrap()); - let w: Vec> = serde_json::from_reader(reader).unwrap(); + // let path = "src/mpt_circuit/tests"; + // let files = fs::read_dir(path).unwrap(); + // let files: Vec = files + // .filter_map(Result::ok) + // .filter(|d| { + // if let Some(e) = d.path().extension() { + // e == "json" + // } else { + // false + // } + // }).collect(); + + // let path = &files[0].path(); + // let mut parts = path.to_str().unwrap().split('-'); + // parts.next(); + // let file = std::fs::File::open(path.clone()); + // let reader = std::io::BufReader::new(file.unwrap()); + let w: Vec> = serde_json::from_str(debug_file).unwrap(); let randomness: Fr = 2.scalar(); @@ -743,3 +742,5 @@ mod tests { } } + +const debug_file: &'static str = "[[1,0,1,0,248,81,0,248,81,0,3,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,160,12,238,76,188,132,183,202,253,232,24,203,94,245,16,89,89,51,190,136,196,16,141,191,3,32,223,60,175,134,134,252,108,0,160,12,238,76,188,132,183,202,253,232,24,203,94,245,16,89,89,51,190,136,196,16,141,191,3,32,223,60,175,134,134,252,108,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,160,174,121,120,114,157,43,164,140,103,235,28,242,186,33,76,152,157,197,109,149,229,229,22,189,233,207,92,195,82,121,240,3,0,160,174,121,120,114,157,43,164,140,103,235,28,242,186,33,76,152,157,197,109,149,229,229,22,189,233,207,92,195,82,121,240,3,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[226,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,165,122,171,104,113,212,176,43,65,48,207,251,142,53,47,186,90,181,22,93,66,192,18,250,18,108,20,25,228,62,211,52,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,165,122,171,104,113,212,176,43,65,48,207,251,142,53,47,186,90,181,22,93,66,192,18,250,18,108,20,25,228,62,211,52,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,17],[248,105,160,32,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,6],[248,105,160,32,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,4],[0,0,160,32,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,18],[184,70,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,68,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,7],[184,70,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,68,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,8],[0,160,86,232,31,23,27,204,85,166,255,131,69,230,146,192,248,110,91,72,224,27,153,108,173,192,1,98,47,181,227,99,180,33,0,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,9],[0,160,86,232,31,23,27,204,85,166,255,131,69,230,146,192,248,110,91,72,224,27,153,108,173,192,1,98,47,181,227,99,180,33,0,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,11],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,10],[226,24,160,165,122,171,104,113,212,176,43,65,48,207,251,142,53,47,186,90,181,22,93,66,192,18,250,18,108,20,25,228,62,211,52,5],[226,24,160,165,122,171,104,113,212,176,43,65,48,207,251,142,53,47,186,90,181,22,93,66,192,18,250,18,108,20,25,228,62,211,52,5],[248,81,128,128,128,160,12,238,76,188,132,183,202,253,232,24,203,94,245,16,89,89,51,190,136,196,16,141,191,3,32,223,60,175,134,134,252,108,128,128,128,128,128,160,174,121,120,114,157,43,164,140,103,235,28,242,186,33,76,152,157,197,109,149,229,229,22,189,233,207,92,195,82,121,240,3,128,128,128,128,128,128,128,5],[248,81,128,128,128,160,12,238,76,188,132,183,202,253,232,24,203,94,245,16,89,89,51,190,136,196,16,141,191,3,32,223,60,175,134,134,252,108,128,128,128,128,128,160,174,121,120,114,157,43,164,140,103,235,28,242,186,33,76,152,157,197,109,149,229,229,22,189,233,207,92,195,82,121,240,3,128,128,128,128,128,128,128,5],[248,105,160,32,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,184,70,248,68,128,128,160,86,232,31,23,27,204,85,166,255,131,69,230,146,192,248,110,91,72,224,27,153,108,173,192,1,98,47,181,227,99,180,33,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,5],[248,105,160,32,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,184,70,248,68,128,128,160,86,232,31,23,27,204,85,166,255,131,69,230,146,192,248,110,91,72,224,27,153,108,173,192,1,98,47,181,227,99,180,33,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,5]]"; \ No newline at end of file From 626f4b93f9e6d8d1e663b3d4160eb53f61036f53 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Tue, 23 May 2023 17:21:30 +0200 Subject: [PATCH 055/102] Fix EXTCODECOPY with empty account (#1429) ### Description We treat empty accounts by storing their code_hash in the RwTable as 0. EXTCODECOPY was obtaining the bytecode length by querying the bytecode table with code_hash=0 on existing accounts, but that entry should be invalid (there's no bytecode with code_hash=0). Skip the bytecode table length lookup when code_hash=0. I've also reintroduced the `Block::debug_print_txs_steps_rw_ops` function, updated to use the new `Block::get_rws` API. This function is not used in the code, but it's very convenient to call it when debugging. ### Issue Link Resolve https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/1190 ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) --- bus-mapping/src/evm/opcodes/extcodecopy.rs | 3 --- bus-mapping/src/state_db.rs | 1 + .../src/evm_circuit/execution/extcodecopy.rs | 18 +++++++++++++----- zkevm-circuits/src/witness/block.rs | 14 ++++++++++++++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/bus-mapping/src/evm/opcodes/extcodecopy.rs b/bus-mapping/src/evm/opcodes/extcodecopy.rs index bd0dc455de..108f5f0d08 100644 --- a/bus-mapping/src/evm/opcodes/extcodecopy.rs +++ b/bus-mapping/src/evm/opcodes/extcodecopy.rs @@ -11,9 +11,6 @@ use eth_types::{Bytecode, GethExecStep, ToAddress, ToWord, H256, U256}; #[derive(Clone, Copy, Debug)] pub(crate) struct Extcodecopy; -// TODO: Update to treat code_hash == 0 as account not_exists once the circuit -// is implemented https://github.com/privacy-scaling-explorations/zkevm-circuits/pull/720 - impl Opcode for Extcodecopy { fn gen_associated_ops( state: &mut CircuitInputStateRef, diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index 91fccbf262..905e41093b 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -8,6 +8,7 @@ use std::collections::{HashMap, HashSet}; lazy_static! { static ref ACCOUNT_ZERO: Account = Account::zero(); + /// Hash value for empty code hash. static ref EMPTY_CODE_HASH: Hash = CodeDB::hash(&[]); /// bytes of empty code hash, in little endian order. pub static ref EMPTY_CODE_HASH_LE: [u8; 32] = { diff --git a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs index ad0d793837..49a24fbb44 100644 --- a/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs +++ b/zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs @@ -9,6 +9,7 @@ use crate::{ Transition, }, from_bytes, + math_gadget::IsZeroGadget, memory_gadget::{MemoryAddressGadget, MemoryCopierGasGadget, MemoryExpansionGadget}, not, select, CachedRegion, Cell, Word, }, @@ -33,6 +34,7 @@ pub(crate) struct ExtcodecopyGadget { reversion_info: ReversionInfo, is_warm: Cell, code_hash: Cell, + not_exists: IsZeroGadget, code_size: Cell, copy_rwc_inc: Cell, memory_expansion: MemoryExpansionGadget, @@ -79,11 +81,14 @@ impl ExecutionGadget for ExtcodecopyGadget { AccountFieldTag::CodeHash, code_hash.expr(), ); - // TODO: If external_address doesn't exist, we will get code_hash = 0. With - // this value, the bytecode_length lookup will not work, and the copy - // from code_hash = 0 will not work. We should use EMPTY_HASH when - // code_hash = 0. - cb.bytecode_length(code_hash.expr(), code_size.expr()); + let not_exists = IsZeroGadget::construct(cb, code_hash.expr()); + let exists = not::expr(not_exists.expr()); + cb.condition(exists.expr(), |cb| { + cb.bytecode_length(code_hash.expr(), code_size.expr()); + }); + cb.condition(not_exists.expr(), |cb| { + cb.require_zero("code_size is zero when non_exists", code_size.expr()); + }); let memory_address = MemoryAddressGadget::construct(cb, memory_offset, memory_length); let memory_expansion = MemoryExpansionGadget::construct(cb, [memory_address.address()]); @@ -148,6 +153,7 @@ impl ExecutionGadget for ExtcodecopyGadget { is_warm, reversion_info, code_hash, + not_exists, code_size, copy_rwc_inc, memory_expansion, @@ -190,6 +196,8 @@ impl ExecutionGadget for ExtcodecopyGadget { let code_hash = block.get_rws(step, 8).account_value_pair().0; self.code_hash .assign(region, offset, region.word_rlc(code_hash))?; + self.not_exists + .assign_value(region, offset, region.word_rlc(code_hash))?; let code_size = if code_hash.is_zero() { 0 diff --git a/zkevm-circuits/src/witness/block.rs b/zkevm-circuits/src/witness/block.rs index 920cd909b0..e3c4de3764 100644 --- a/zkevm-circuits/src/witness/block.rs +++ b/zkevm-circuits/src/witness/block.rs @@ -54,6 +54,20 @@ pub struct Block { } impl Block { + /// For each tx, for each step, print the rwc at the beginning of the step, + /// and all the rw operations of the step. + pub(crate) fn debug_print_txs_steps_rw_ops(&self) { + for (tx_idx, tx) in self.txs.iter().enumerate() { + println!("tx {}", tx_idx); + for step in &tx.steps { + println!(" step {:?} rwc: {}", step.exec_state, step.rwc.0); + for rw_idx in 0..step.bus_mapping_instance.len() { + println!(" - {:?}", self.get_rws(step, rw_idx)); + } + } + } + } + /// Get a read-write record pub(crate) fn get_rws(&self, step: &ExecStep, index: usize) -> Rw { self.rws[step.rw_index(index)] From dbe67c86bb322ee25816fd58429e3292f6cbae1f Mon Sep 17 00:00:00 2001 From: Eduard S Date: Thu, 25 May 2023 09:51:53 +0200 Subject: [PATCH 056/102] [CREATE Part A (updated)] Modification to Copy Circuit (#1419) ### Description NOTE: This is an updated version of https://github.com/privacy-scaling-explorations/zkevm-circuits/pull/1356 This is Part A of a 3 part pull request to add support for `CREATE`/`CREATE2` opcodes. Part A: https://github.com/privacy-scaling-explorations/zkevm-circuits/pull/1356 Part B: https://github.com/privacy-scaling-explorations/zkevm-circuits/pull/1357 Part C: https://github.com/privacy-scaling-explorations/zkevm-circuits/pull/1358 ### Issue Link #1130 ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents As part of the bigger additions needed for the `CREATE`/`CREATE2` opcodes' gadget, this PR adds support for the copy circuit to "always" have a value accumulator field `value_acc`. ### Rationale We need a value accumulator (of the random linear combination) in order to get the `RLC(bytes)` for the bytes copied from `Memory` to `Bytecode` (specifically the init code). This RLC is later used to do a lookup to the Keccak table to check the value of `keccak256(init_code)`. ### How Has This Been Tested? The existing tests for copy circuit pass for the updated constraints on the copy circuit. --------- Co-authored-by: Rohit Narurkar Co-authored-by: KimiWu --- mock/src/test_ctx.rs | 2 +- zkevm-circuits/src/copy_circuit.rs | 132 +++++++++++------- .../evm_circuit/execution/return_revert.rs | 29 ++-- zkevm-circuits/src/evm_circuit/util.rs | 13 ++ zkevm-circuits/src/table/copy_table.rs | 32 ++--- 5 files changed, 128 insertions(+), 80 deletions(-) diff --git a/mock/src/test_ctx.rs b/mock/src/test_ctx.rs index befff9f3e0..4c70d309c4 100644 --- a/mock/src/test_ctx.rs +++ b/mock/src/test_ctx.rs @@ -76,7 +76,7 @@ pub use external_tracer::LoggerConfig; /// // Now we can start generating the traces and items we need to inspect /// // the behaviour of the generated env. /// ``` -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TestContext { /// chain id pub chain_id: Word, diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs index 8d283abb8c..cb9de0dc47 100644 --- a/zkevm-circuits/src/copy_circuit.rs +++ b/zkevm-circuits/src/copy_circuit.rs @@ -50,6 +50,8 @@ pub struct CopyCircuitConfig { pub is_last: Column, /// The value copied in this copy step. pub value: Column, + /// Random linear combination accumulator value. + pub value_acc_rlc: Column, /// Whether the row is padding. pub is_pad: Column, /// In case of a bytecode tag, this denotes whether or not the copied byte @@ -107,7 +109,8 @@ impl SubCircuitConfig for CopyCircuitConfig { ) -> Self { let q_step = meta.complex_selector(); let is_last = meta.advice_column(); - let value = meta.advice_column_in(SecondPhase); + let value = meta.advice_column(); + let value_acc_rlc = meta.advice_column_in(SecondPhase); let is_code = meta.advice_column(); let is_pad = meta.advice_column(); let is_first = copy_table.is_first; @@ -225,23 +228,36 @@ impl SubCircuitConfig for CopyCircuitConfig { rw_diff, ); }); - cb.condition( - and::expr([ - meta.query_advice(is_last, Rotation::cur()), - tag.value_equals(CopyDataType::RlcAcc, Rotation::cur())(meta), - ]), - |cb| { - cb.require_equal( - "value == rlc_acc at the last row for RlcAcc", - meta.query_advice(value, Rotation::cur()), - meta.query_advice(rlc_acc, Rotation::cur()), - ); - }, - ); cb.gate(meta.query_fixed(q_enable, Rotation::cur())) }); + meta.create_gate( + "Last Step (check value accumulator) Memory => Bytecode or RlcAcc", + |meta: &mut halo2_proofs::plonk::VirtualCells| { + let mut cb = BaseConstraintBuilder::default(); + + cb.require_equal( + "value_acc_rlc == rlc_acc on the last row", + meta.query_advice(value_acc_rlc, Rotation::next()), + meta.query_advice(rlc_acc, Rotation::next()), + ); + + cb.gate(and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(is_last, Rotation::next()), + // To build a selector expression just having 0 when false and != 0 when true + // is enough, so we could replace the `or` by a `+`. This + // would give 2 when both expressions are true + // but it's fine. + and::expr([ + tag.value_equals(CopyDataType::Memory, Rotation::cur())(meta), + tag.value_equals(CopyDataType::Bytecode, Rotation::next())(meta), + ]) + tag.value_equals(CopyDataType::RlcAcc, Rotation::next())(meta), + ])) + }, + ); + meta.create_gate("verify step (q_step == 1)", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -253,10 +269,10 @@ impl SubCircuitConfig for CopyCircuitConfig { ]), ); cb.condition( - not::expr(meta.query_advice(is_last, Rotation::next())) - * (not::expr(tag.value_equals(CopyDataType::Padding, Rotation::cur())( - meta, - ))), + not::expr(or::expr([ + meta.query_advice(is_last, Rotation::next()), + tag.value_equals(CopyDataType::Padding, Rotation::cur())(meta), + ])), |cb| { cb.require_equal( "bytes_left == bytes_left_next + 1 for non-last step", @@ -265,25 +281,38 @@ impl SubCircuitConfig for CopyCircuitConfig { ); }, ); + cb.condition(meta.query_advice(is_first, Rotation::cur()), |cb| { + cb.require_equal( + "value == value_acc_rlc at every first copy event", + meta.query_advice(value, Rotation::cur()), + meta.query_advice(value_acc_rlc, Rotation::cur()), + ); + }); + cb.require_equal( + "write value == read value", + meta.query_advice(value, Rotation::cur()), + meta.query_advice(value, Rotation::next()), + ); + cb.require_equal( + "value_acc_rlc is same for read-write rows", + meta.query_advice(value_acc_rlc, Rotation::cur()), + meta.query_advice(value_acc_rlc, Rotation::next()), + ); cb.condition( - not::expr(tag.value_equals(CopyDataType::RlcAcc, Rotation::next())( - meta, - )), + and::expr([ + not::expr(meta.query_advice(is_last, Rotation::next())), + not::expr(meta.query_advice(is_pad, Rotation::cur())), + ]), |cb| { cb.require_equal( - "write value == read value (if not rlc acc)", - meta.query_advice(value, Rotation::cur()), - meta.query_advice(value, Rotation::next()), + "value_acc_rlc(2) == value_acc_rlc(0) * r + value(2)", + meta.query_advice(value_acc_rlc, Rotation(2)), + meta.query_advice(value_acc_rlc, Rotation::cur()) + * challenges.keccak_input() + + meta.query_advice(value, Rotation(2)), ); }, ); - cb.condition(meta.query_advice(is_first, Rotation::cur()), |cb| { - cb.require_equal( - "write value == read value (is_first == 1)", - meta.query_advice(value, Rotation::cur()), - meta.query_advice(value, Rotation::next()), - ); - }); cb.require_zero( "value == 0 when is_pad == 1 for read", and::expr([ @@ -301,26 +330,7 @@ impl SubCircuitConfig for CopyCircuitConfig { meta.query_advice(is_pad, Rotation::next()), ); - cb.gate(meta.query_selector(q_step)) - }); - - meta.create_gate("verify_step (q_step == 0)", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - cb.require_equal( - "rows[2].value == rows[0].value * r + rows[1].value", - meta.query_advice(value, Rotation(2)), - meta.query_advice(value, Rotation::cur()) * challenges.keccak_input() - + meta.query_advice(value, Rotation::next()), - ); - - cb.gate(and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_selector(q_step)), - not::expr(meta.query_advice(is_last, Rotation::cur())), - tag.value_equals(CopyDataType::RlcAcc, Rotation::cur())(meta), - not::expr(meta.query_advice(is_pad, Rotation::cur())), - ])) + cb.gate(and::expr([meta.query_selector(q_step)])) }); meta.lookup_any("Memory lookup", |meta| { @@ -405,6 +415,7 @@ impl SubCircuitConfig for CopyCircuitConfig { q_step, is_last, value, + value_acc_rlc, is_pad, is_code, q_enable, @@ -466,9 +477,15 @@ impl CopyCircuitConfig { )?; // is_last, value, is_pad, is_code - for (column, &(value, label)) in [self.is_last, self.value, self.is_pad, self.is_code] - .iter() - .zip_eq(circuit_row) + for (column, &(value, label)) in [ + self.is_last, + self.value, + self.value_acc_rlc, + self.is_pad, + self.is_code, + ] + .iter() + .zip_eq(circuit_row) { region.assign_advice( || format!("{} at row: {}", label, *offset), @@ -621,6 +638,13 @@ impl CopyCircuitConfig { *offset, || Value::known(F::ZERO), )?; + // value_acc_rlc + region.assign_advice( + || format!("assign value_acc_rlc {}", *offset), + self.value_acc_rlc, + *offset, + || Value::known(F::ZERO), + )?; // rlc_acc region.assign_advice( || format!("assign rlc_acc {}", *offset), diff --git a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs index cad355c2bc..f5dbefa402 100644 --- a/zkevm-circuits/src/evm_circuit/execution/return_revert.rs +++ b/zkevm-circuits/src/evm_circuit/execution/return_revert.rs @@ -27,6 +27,7 @@ pub(crate) struct ReturnRevertGadget { opcode: Cell, range: MemoryAddressGadget, + deployed_code_rlc: Cell, is_success: Cell, restore_context: RestoreContextGadget, @@ -94,11 +95,12 @@ impl ExecutionGadget for ReturnRevertGadget { let is_contract_deployment = is_create.clone() * is_success.expr() * not::expr(copy_rw_increase_is_zero.expr()); - let (caller_id, address, reversion_info, code_hash) = + let (caller_id, address, reversion_info, code_hash, deployed_code_rlc) = cb.condition(is_contract_deployment.clone(), |cb| { // We don't need to place any additional constraints on code_hash because the // copy circuit enforces that it is the hash of the bytes in the copy lookup. let code_hash = cb.query_cell_phase2(); + let deployed_code_rlc = cb.query_cell_phase2(); cb.copy_table_lookup( cb.curr.state.call_id.expr(), CopyDataType::Memory.expr(), @@ -108,7 +110,7 @@ impl ExecutionGadget for ReturnRevertGadget { range.address(), 0.expr(), range.length(), - 0.expr(), + deployed_code_rlc.expr(), copy_rw_increase.expr(), ); @@ -127,7 +129,13 @@ impl ExecutionGadget for ReturnRevertGadget { Some(&mut reversion_info), ); - (caller_id, address, reversion_info, code_hash) + ( + caller_id, + address, + reversion_info, + code_hash, + deployed_code_rlc, + ) }); // Case B in the specs. @@ -218,6 +226,7 @@ impl ExecutionGadget for ReturnRevertGadget { Self { opcode, range, + deployed_code_rlc, is_success, copy_length, copy_rw_increase, @@ -279,6 +288,11 @@ impl ExecutionGadget for ReturnRevertGadget { let values: Vec<_> = (3..3 + length.as_usize()) .map(|index| block.get_rws(step, index).memory_value()) .collect(); + self.deployed_code_rlc.assign( + region, + offset, + region.keccak_rlc(&values.iter().rev().cloned().collect::>()), + )?; let mut code_hash = CodeDB::hash(&values).to_fixed_bytes(); code_hash.reverse(); self.code_hash.assign( @@ -614,10 +628,8 @@ mod test { PUSH1(0) // dest offset RETURNDATACOPY }); - - let block: GethData = TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode.clone()) - .unwrap() - .into(); + let test_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode.clone()).unwrap(); + let block: GethData = test_ctx.clone().into(); // collect return opcode, retrieve next step, assure both contract create // successfully @@ -648,8 +660,7 @@ mod test { .iter() .for_each(|size| assert_eq!(size, &Word::zero())); - let text_ctx = TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(); - CircuitTestBuilder::new_from_test_ctx(text_ctx).run(); + CircuitTestBuilder::new_from_test_ctx(test_ctx).run(); } #[test] diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs index de2a71bad5..f8136f55db 100644 --- a/zkevm-circuits/src/evm_circuit/util.rs +++ b/zkevm-circuits/src/evm_circuit/util.rs @@ -193,10 +193,23 @@ impl<'r, 'b, F: Field> CachedRegion<'r, 'b, F> { .evm_word() .map(|r| rlc::value(&n.to_le_bytes(), r)) } + + pub fn keccak_rlc(&self, le_bytes: &[u8]) -> Value { + self.challenges + .keccak_input() + .map(|r| rlc::value(le_bytes, r)) + } + pub fn empty_code_hash_rlc(&self) -> Value { self.word_rlc(CodeDB::empty_code_hash().to_word()) } + pub fn code_hash(&self, n: U256) -> Value { + self.challenges + .evm_word() + .map(|r| rlc::value(&n.to_le_bytes(), r)) + } + /// Constrains a cell to have a constant value. /// /// Returns an error if the cell is in a column where equality has not been diff --git a/zkevm-circuits/src/table/copy_table.rs b/zkevm-circuits/src/table/copy_table.rs index 9db69d7c27..a48761229d 100644 --- a/zkevm-circuits/src/table/copy_table.rs +++ b/zkevm-circuits/src/table/copy_table.rs @@ -1,7 +1,7 @@ use super::*; type CopyTableRow = [(Value, &'static str); 8]; -type CopyCircuitRow = [(Value, &'static str); 4]; +type CopyCircuitRow = [(Value, &'static str); 5]; /// Copy Table, used to verify copies of byte chunks between Memory, Bytecode, /// TxLogs and TxCallData. @@ -61,7 +61,7 @@ impl CopyTable { ) -> Vec<(CopyDataType, CopyTableRow, CopyCircuitRow)> { let mut assignments = Vec::new(); // rlc_acc - let rlc_acc = if copy_event.dst_type == CopyDataType::RlcAcc { + let rlc_acc = { let values = copy_event .bytes .iter() @@ -70,8 +70,6 @@ impl CopyTable { challenges .keccak_input() .map(|keccak_input| rlc::value(values.iter().rev(), keccak_input)) - } else { - Value::known(F::ZERO) }; let mut value_acc = Value::known(F::ZERO); for (step_idx, (is_read_step, copy_step)) in copy_event @@ -146,17 +144,11 @@ impl CopyTable { // bytes_left let bytes_left = u64::try_from(copy_event.bytes.len() * 2 - step_idx).unwrap() / 2; // value - let value = if copy_event.dst_type == CopyDataType::RlcAcc { - if is_read_step { - Value::known(F::from(copy_step.value as u64)) - } else { - value_acc = value_acc * challenges.keccak_input() - + Value::known(F::from(copy_step.value as u64)); - value_acc - } - } else { - Value::known(F::from(copy_step.value as u64)) - }; + let value = Value::known(F::from(copy_step.value as u64)); + // value_acc + if is_read_step { + value_acc = value_acc * challenges.keccak_input() + value; + } // is_pad let is_pad = Value::known(F::from( (is_read_step && copy_step_addr >= copy_event.src_addr_end) as u64, @@ -176,7 +168,14 @@ impl CopyTable { "src_addr_end", ), (Value::known(F::from(bytes_left)), "bytes_left"), - (rlc_acc, "rlc_acc"), + ( + match (copy_event.src_type, copy_event.dst_type) { + (CopyDataType::Memory, CopyDataType::Bytecode) => rlc_acc, + (_, CopyDataType::RlcAcc) => rlc_acc, + _ => Value::known(F::ZERO), + }, + "rlc_acc", + ), ( Value::known(F::from(copy_event.rw_counter(step_idx))), "rw_counter", @@ -189,6 +188,7 @@ impl CopyTable { [ (is_last, "is_last"), (value, "value"), + (value_acc, "value_acc"), (is_pad, "is_pad"), (is_code, "is_code"), ], From 5e1d35e8aaae9dbf444b1c13b27785920397621a Mon Sep 17 00:00:00 2001 From: Kimi Wu Date: Fri, 26 May 2023 12:12:09 +0800 Subject: [PATCH 057/102] Feat/CREATE Part B - Error cases that will be handled within opcode gadgets (#1425) ### Description **NOTE: This is an updated version of https://github.com/privacy-scaling-explorations/zkevm-circuits/pull/1357** This PR is actually based on top of #1419 ### Issue Link #1130 ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents Error types for insufficient balance and nonce overflow. These are supporting changes required for the CREATE/CREATE2 opcodes' gadget. ### Rationale The above errors will be handled within the CREATE/CREATE2 opcodes' gadget. In case of insufficient balance, it is also handled in the CallOp gadget for call related opcodes. --------- Co-authored-by: Rohit Narurkar --- .../circuit_input_builder/input_state_ref.rs | 35 +++++++++++++-- .../src/circuit_input_builder/tracer_tests.rs | 8 ++-- bus-mapping/src/error.rs | 43 ++++++++++++++++--- bus-mapping/src/evm/opcodes.rs | 40 +++++++++++------ zkevm-circuits/src/evm_circuit/execution.rs | 9 ---- zkevm-circuits/src/evm_circuit/step.rs | 22 ++++++++-- 6 files changed, 119 insertions(+), 38 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index ffbbc00707..9f5b94c9df 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -6,7 +6,10 @@ use super::{ TransactionContext, }; use crate::{ - error::{get_step_reported_error, ExecError}, + error::{ + get_step_reported_error, DepthError, ExecError, InsufficientBalanceError, + NonceUintOverflowError, + }, exec_trace::OperationRef, operation::{ AccountField, AccountOp, CallContextField, CallContextOp, MemoryOp, Op, OpEnum, Operation, @@ -1290,7 +1293,14 @@ impl<'a> CircuitInputStateRef<'a> { && next_pc != 0 { if step.depth == 1025 { - return Ok(Some(ExecError::Depth)); + return Ok(Some(ExecError::Depth(match step.op { + OpcodeId::CALL | OpcodeId::CALLCODE => DepthError::Call, + OpcodeId::CREATE => DepthError::Create, + OpcodeId::CREATE2 => DepthError::Create2, + op => { + unreachable!("Depth error unexpected for opcode: {:?}", op) + } + }))); } let sender = self.call()?.address; @@ -1299,7 +1309,26 @@ impl<'a> CircuitInputStateRef<'a> { return Err(Error::AccountNotFound(sender)); } if account.balance < value { - return Ok(Some(ExecError::InsufficientBalance)); + return Ok(Some(ExecError::InsufficientBalance(match step.op { + OpcodeId::CALL | OpcodeId::CALLCODE => InsufficientBalanceError::Call, + OpcodeId::CREATE => InsufficientBalanceError::Create, + OpcodeId::CREATE2 => InsufficientBalanceError::Create2, + op => { + unreachable!("insufficient balance error unexpected for opcode: {:?}", op) + } + }))); + } + + // Nonce Uint overflow + // If user's nonce is equal u64::MAX, nonce will be overflow in this call + // Nonce is u64 so it's impossible to larger than u64::MAX, that's why we're using `==` + // here. + if account.nonce == u64::MAX { + return Ok(Some(ExecError::NonceUintOverflow(match step.op { + OpcodeId::CREATE => NonceUintOverflowError::Create, + OpcodeId::CREATE2 => NonceUintOverflowError::Create2, + op => unreachable!("Nonce Uint overflow error unexpected for opcode: {:?}", op), + }))); } // Address collision diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index e311af4495..ad6d106bf7 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -1,7 +1,7 @@ use super::*; use crate::{ circuit_input_builder::access::gen_state_access_trace, - error::{ExecError, OogError}, + error::{DepthError, ExecError, InsufficientBalanceError, OogError}, geth_errors::{ GETH_ERR_GAS_UINT_OVERFLOW, GETH_ERR_OUT_OF_GAS, GETH_ERR_STACK_OVERFLOW, GETH_ERR_STACK_UNDERFLOW, @@ -208,7 +208,7 @@ fn tracer_err_depth() { let mut builder = CircuitInputBuilderTx::new(&block, step); assert_eq!( builder.state_ref().get_step_err(step, next_step).unwrap(), - Some(ExecError::Depth) + Some(ExecError::Depth(DepthError::Call)) ); } @@ -274,7 +274,9 @@ fn tracer_err_insufficient_balance() { let mut builder = CircuitInputBuilderTx::new(&block, step); assert_eq!( builder.state_ref().get_step_err(step, next_step).unwrap(), - Some(ExecError::InsufficientBalance) + Some(ExecError::InsufficientBalance( + InsufficientBalanceError::Call + )) ); } diff --git a/bus-mapping/src/error.rs b/bus-mapping/src/error.rs index cf3e4d8c46..dca1721456 100644 --- a/bus-mapping/src/error.rs +++ b/bus-mapping/src/error.rs @@ -98,6 +98,37 @@ pub enum OogError { SelfDestruct, } +/// Insufficient balance errors by opcode/state. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum InsufficientBalanceError { + /// Insufficient balance during CALL/CALLCODE opcode. + Call, + /// Insufficient balance during CREATE opcode. + Create, + /// Insufficient balance during CREATE2 opcode. + Create2, +} + +/// Nonce uint overflow errors by opcode/state. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum NonceUintOverflowError { + /// Nonce uint overflow during CREATE opcode. + Create, + /// Nonce uint overflow during CREATE2 opcode. + Create2, +} + +/// Call depth errors by opcode/state. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum DepthError { + /// Call depth errors in CALL/CALLCODE opcode. + Call, + /// Call depth errors in CREATE opcode. + Create, + /// Call depth errors in CREATE2 opcode. + Create2, +} + /// EVM Execution Error #[derive(Clone, Debug, PartialEq, Eq)] pub enum ExecError { @@ -112,11 +143,11 @@ pub enum ExecError { /// For SSTORE, LOG0, LOG1, LOG2, LOG3, LOG4, CREATE, CALL, CREATE2, /// SELFDESTRUCT WriteProtection, - /// For CALL, CALLCODE, DELEGATECALL, STATICCALL - Depth, - /// For CALL, CALLCODE - InsufficientBalance, - /// For CREATE, CREATE2 + /// For CALL, CALLCODE, DELEGATECALL, STATICCALL, CREATE, CREATE2 + Depth(DepthError), + /// For CALL, CALLCODE, CREATE, CREATE2 + InsufficientBalance(InsufficientBalanceError), + /// For CREATE2 ContractAddressCollision, /// contract must not begin with 0xef due to EIP #3541 EVM Object Format /// (EOF) @@ -129,6 +160,8 @@ pub enum ExecError { CodeStoreOutOfGas, /// For RETURN in a CREATE, CREATE2 MaxCodeSizeExceeded, + /// For CREATE, CREATE2 + NonceUintOverflow(NonceUintOverflowError), } // TODO: Move to impl block. diff --git a/bus-mapping/src/evm/opcodes.rs b/bus-mapping/src/evm/opcodes.rs index 781d724882..cb4326ac66 100644 --- a/bus-mapping/src/evm/opcodes.rs +++ b/bus-mapping/src/evm/opcodes.rs @@ -1,7 +1,7 @@ //! Definition of each opcode of the EVM. use crate::{ circuit_input_builder::{CircuitInputStateRef, ExecState, ExecStep}, - error::{ExecError, OogError}, + error::{DepthError, ExecError, InsufficientBalanceError, NonceUintOverflowError, OogError}, evm::OpcodeId, operation::TxAccessListAccountOp, Error, @@ -271,10 +271,7 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps { } } -fn fn_gen_error_state_associated_ops( - geth_step: &GethExecStep, - error: &ExecError, -) -> Option { +fn fn_gen_error_state_associated_ops(error: &ExecError) -> Option { match error { ExecError::InvalidJump => Some(InvalidJump::gen_associated_ops), ExecError::InvalidOpcode => Some(ErrorSimple::gen_associated_ops), @@ -287,16 +284,31 @@ fn fn_gen_error_state_associated_ops( ExecError::StackOverflow => Some(ErrorSimple::gen_associated_ops), ExecError::StackUnderflow => Some(ErrorSimple::gen_associated_ops), // call & callcode can encounter InsufficientBalance error, Use pop-7 generic CallOpcode - ExecError::InsufficientBalance => Some(CallOpcode::<7>::gen_associated_ops), + ExecError::InsufficientBalance(InsufficientBalanceError::Call) => { + Some(CallOpcode::<7>::gen_associated_ops) + } + // create & create2 can encounter insufficient balance. + ExecError::InsufficientBalance(InsufficientBalanceError::Create) => { + Some(DummyCreate::::gen_associated_ops) + } + ExecError::InsufficientBalance(InsufficientBalanceError::Create2) => { + Some(DummyCreate::::gen_associated_ops) + } + // only create2 may cause ContractAddressCollision error, so use DummyCreate::. + ExecError::ContractAddressCollision => Some(DummyCreate::::gen_associated_ops), + // create & create2 can encounter nonce uint overflow. + ExecError::NonceUintOverflow(NonceUintOverflowError::Create) => { + Some(DummyCreate::::gen_associated_ops) + } + ExecError::NonceUintOverflow(NonceUintOverflowError::Create2) => { + Some(DummyCreate::::gen_associated_ops) + } ExecError::WriteProtection => Some(ErrorWriteProtection::gen_associated_ops), ExecError::ReturnDataOutOfBounds => Some(ErrorReturnDataOutOfBound::gen_associated_ops), - ExecError::Depth => { - let op = geth_step.op; - if !op.is_call() { - evm_unimplemented!("TODO: ErrDepth for CREATE is not implemented yet"); - } - Some(fn_gen_associated_ops(&op)) - } + // call, callcode, create & create2 can encounter DepthError error, + ExecError::Depth(DepthError::Call) => Some(CallOpcode::<7>::gen_associated_ops), + ExecError::Depth(DepthError::Create) => Some(DummyCreate::::gen_associated_ops), + ExecError::Depth(DepthError::Create2) => Some(DummyCreate::::gen_associated_ops), // more future errors place here _ => { evm_unimplemented!("TODO: error state {:?} not implemented", error); @@ -342,7 +354,7 @@ pub fn gen_associated_ops( // TODO: after more error state handled, refactor all error handling in // fn_gen_error_state_associated_ops method // For exceptions that have been implemented - if let Some(fn_gen_error_ops) = fn_gen_error_state_associated_ops(geth_step, &exec_error) { + if let Some(fn_gen_error_ops) = fn_gen_error_state_associated_ops(&exec_error) { return fn_gen_error_ops(state, geth_steps); } else { // For exceptions that fail to enter next call context, we need diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs index ff3e48e92d..ec26da51cd 100644 --- a/zkevm-circuits/src/evm_circuit/execution.rs +++ b/zkevm-circuits/src/evm_circuit/execution.rs @@ -1280,9 +1280,6 @@ impl ExecutionConfig { assign_exec_step!(self.error_stack) } - ExecutionState::ErrorInsufficientBalance => { - assign_exec_step!(self.call_op_gadget) - } ExecutionState::ErrorInvalidJump => { assign_exec_step!(self.error_invalid_jump) } @@ -1292,12 +1289,6 @@ impl ExecutionConfig { ExecutionState::ErrorWriteProtection => { assign_exec_step!(self.error_write_protection) } - ExecutionState::ErrorDepth => { - assign_exec_step!(self.error_depth) - } - ExecutionState::ErrorContractAddressCollision => { - assign_exec_step!(self.error_contract_address_collision) - } ExecutionState::ErrorInvalidCreationCode => { assign_exec_step!(self.error_invalid_creation_code) } diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index 61323f557a..77847644fe 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -9,7 +9,7 @@ use crate::{ }; use bus_mapping::{ circuit_input_builder::ExecState, - error::{ExecError, OogError}, + error::{DepthError, ExecError, InsufficientBalanceError, NonceUintOverflowError, OogError}, evm::OpcodeId, }; use eth_types::{evm_unimplemented, Field, ToWord}; @@ -131,9 +131,23 @@ impl From<&ExecError> for ExecutionState { ExecError::InvalidOpcode => ExecutionState::ErrorInvalidOpcode, ExecError::StackOverflow | ExecError::StackUnderflow => ExecutionState::ErrorStack, ExecError::WriteProtection => ExecutionState::ErrorWriteProtection, - ExecError::Depth => ExecutionState::ErrorDepth, - ExecError::InsufficientBalance => ExecutionState::ErrorInsufficientBalance, - ExecError::ContractAddressCollision => ExecutionState::ErrorContractAddressCollision, + ExecError::Depth(depth_error) => match depth_error { + DepthError::Call => ExecutionState::CALL_OP, + DepthError::Create => ExecutionState::CREATE, + DepthError::Create2 => ExecutionState::CREATE2, + }, + ExecError::InsufficientBalance(insufficient_balance_err) => { + match insufficient_balance_err { + InsufficientBalanceError::Call => ExecutionState::CALL_OP, + InsufficientBalanceError::Create => ExecutionState::CREATE, + InsufficientBalanceError::Create2 => ExecutionState::CREATE2, + } + } + ExecError::NonceUintOverflow(nonce_overflow_err) => match nonce_overflow_err { + NonceUintOverflowError::Create => ExecutionState::CREATE, + NonceUintOverflowError::Create2 => ExecutionState::CREATE2, + }, + ExecError::ContractAddressCollision => ExecutionState::CREATE2, ExecError::InvalidCreationCode => ExecutionState::ErrorInvalidCreationCode, ExecError::InvalidJump => ExecutionState::ErrorInvalidJump, ExecError::ReturnDataOutOfBounds => ExecutionState::ErrorReturnDataOutOfBound, From 96d2e3c58d19423d062eb78ba3bd2310b9de6b31 Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Tue, 30 May 2023 01:02:42 +0800 Subject: [PATCH 058/102] Remove release drafter (#1436) ### Description The release drafter was used to create a list of changes in the release note. As Github now provides this functionality by native, there's no need to maintain this CI script. ### Issue Link [_link issue here_] ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update --- .github/release-drafter.yml | 29 ----------------------------- .github/workflows/draft.yml | 16 ---------------- 2 files changed, 45 deletions(-) delete mode 100644 .github/release-drafter.yml delete mode 100644 .github/workflows/draft.yml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml deleted file mode 100644 index 950aa422ea..0000000000 --- a/.github/release-drafter.yml +++ /dev/null @@ -1,29 +0,0 @@ -categories: - - title: "Changes in the bus-mapping" - label: "crate-bus-mapping" - - title: "Changes in circuit-benchmarks" - label: "crate-circuit-benchmarks" - - title: "Changes in eth-types" - label: "crate-eth-types" - - title: "Changes in external-tracer" - label: "crate-external-tracer" - - title: "Changes in gadgets" - label: "crate-gadgets" - - title: "Changes in geth-utils" - label: "crate-geth-utils" - - title: "Changes in integration-tests" - label: "crate-integration-tests" - - title: "Changes in Keccak" - label: "crate-keccak" - - title: "Changes in mock" - label: "crate-mock" - - title: "Changes in prover" - label: "crate-prover" - - title: "Changes in the zkevm-circuits" - label: "crate-zkevm-circuits" -version-resolver: - default: minor -prerelease: true -template: | - ## What’s Changed - $CHANGES diff --git a/.github/workflows/draft.yml b/.github/workflows/draft.yml deleted file mode 100644 index bb67d4a5b6..0000000000 --- a/.github/workflows/draft.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Release Drafter - -on: - push: - branches: - - main - -jobs: - update_release_draft: - runs-on: ubuntu-latest - steps: - - uses: release-drafter/release-drafter@v5 - with: - config-name: release-drafter.yml - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 7bfe63528c1fa81768f354ab7b6f4a3726bebfb5 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Tue, 30 May 2023 12:09:06 +0800 Subject: [PATCH 059/102] CachedRegion init & descrption --- zkevm-circuits/src/mpt_circuit/helpers.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index b9f78c54c9..92ed4ed0f1 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -811,6 +811,10 @@ impl MPTConstraintBuilder { base: ConstraintBuilder::new(max_degree, cell_manager), } } + + pub(crate) fn is_descr_disabled(&self) -> bool { + self.base.is_descr_disabled() + } pub(crate) fn query_bool(&mut self) -> Cell { self.base.query_bool() @@ -818,11 +822,11 @@ impl MPTConstraintBuilder { pub(crate) fn query_byte(&mut self) -> Cell { // TODO(Brecht): fix - self.base.query_one(EvmCellType::StoragePhase1) + self.base.query_one(EvmCellType::LookupByte) } pub(crate) fn query_bytes(&mut self) -> [Cell; N] { - self.base.query_cells_dyn(EvmCellType::StoragePhase1, N) + self.base.query_cells_dyn(EvmCellType::LookupByte, N) .try_into() .unwrap() } @@ -841,7 +845,6 @@ impl MPTConstraintBuilder { .unwrap() } - // Pass through to base pub(crate) fn require_equal( &mut self, name: &'static str, @@ -873,6 +876,15 @@ impl MPTConstraintBuilder { self.base.lookup(description, tag, values) } + pub(crate) fn lookup_table>( + &mut self, + description: &'static str, + tag: S, + values: Vec> + ) { + self.base.lookup_table(description, tag, values) + } + pub(crate) fn push_condition(&mut self, condition: Expression) { self.base.push_condition(condition) } From bc1d2e1211f18e299e8668ea01cd9cb57f76d5ed Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Wed, 31 May 2023 14:42:42 +0800 Subject: [PATCH 060/102] CachedRegion included & debugged CM --- .../src/circuit_tools/cached_region.rs | 235 ++++++++---------- .../src/circuit_tools/cell_manager.rs | 134 +++++++--- .../src/circuit_tools/constraint_builder.rs | 228 ++++++++++++++--- zkevm-circuits/src/circuit_tools/memory.rs | 4 + .../src/circuit_tools/tests/util.rs | 12 +- zkevm-circuits/src/mpt_circuit.rs | 121 +++------ .../src/mpt_circuit/account_leaf.rs | 51 ++-- .../src/mpt_circuit/extension_branch.rs | 29 ++- zkevm-circuits/src/mpt_circuit/start.rs | 20 +- .../src/mpt_circuit/storage_leaf.rs | 43 ++-- 10 files changed, 530 insertions(+), 347 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools/cached_region.rs b/zkevm-circuits/src/circuit_tools/cached_region.rs index 7649975777..fc1b0f951b 100644 --- a/zkevm-circuits/src/circuit_tools/cached_region.rs +++ b/zkevm-circuits/src/circuit_tools/cached_region.rs @@ -9,7 +9,7 @@ use halo2_proofs::{ }; use itertools::Itertools; use std::{ - hash::{Hash, Hasher}, + hash::{Hash, Hasher}, collections::HashMap, }; use super::cell_manager::CellTypeTrait; @@ -24,160 +24,139 @@ impl]>> ChallengeSet for V { } } +pub trait MacroDescr { + fn is_descr_disabled(&self) -> bool; +} + +impl<'r, F: Field> MacroDescr for Region<'r, F> { + fn is_descr_disabled(&self) -> bool { + false + } +} + + pub struct CachedRegion<'r, 'b, F: Field, S: ChallengeSet> { region: &'r mut Region<'b, F>, - advice: Vec>, + advice: HashMap<(usize, usize), F>, challenges: &'r S, - advice_columns: Vec>, - width_start: usize, - height_start: usize, + disable_description: bool, } impl<'r, 'b, F: Field, S: ChallengeSet> CachedRegion<'r, 'b, F, S> { - /// New cached region pub(crate) fn new( region: &'r mut Region<'b, F>, challenges: &'r S, - advice_columns: Vec>, - height: usize, - height_start: usize, ) -> Self { Self { region, - advice: vec![vec![F::zero(); height]; advice_columns.len()], + advice: HashMap::new(), challenges, - width_start: advice_columns[0].index(), - height_start, - advice_columns, - } - } - - /// This method replicates the assignment of 1 row at height_start (which - /// must be already assigned via the CachedRegion) into a range of rows - /// indicated by offset_begin, offset_end. It can be used as a "quick" - /// path for assignment for repeated padding rows. - pub fn replicate_assignment_for_range( - &mut self, - annotation: A, - offset_begin: usize, - offset_end: usize, - ) -> Result<(), Error> - where - A: Fn() -> AR, - AR: Into, - { - for (v, column) in self - .advice - .iter() - .map(|values| values[0]) - .zip_eq(self.advice_columns.iter()) - { - if v.is_zero_vartime() { - continue; - } - let annotation: &String = &annotation().into(); - for offset in offset_begin..offset_end { - self.region - .assign_advice(|| annotation, *column, offset, || Value::known(v))?; - } - } - - Ok(()) - } - - /// Assign an advice column value (witness). - pub fn assign_advice<'v, V, VR, A, AR>( - &'v mut self, - annotation: A, - column: Column, - offset: usize, - to: V, - ) -> Result, Error> - where - V: Fn() -> Value + 'v, - for<'vr> Assigned: From<&'vr VR>, - A: Fn() -> AR, - AR: Into, - { - // Actually set the value - let res = self.region.assign_advice(annotation, column, offset, &to); - // Cache the value - // Note that the `value_field` in `AssignedCell` might be `Value::unkonwn` if - // the column has different phase than current one, so we call to `to` - // again here to cache the value. - if res.is_ok() { - to().map(|f| { - self.advice[column.index() - self.width_start][offset - self.height_start] = - Assigned::from(&f).evaluate(); - }); + disable_description: false, } - res } - pub fn assign_fixed<'v, V, VR, A, AR>( - &'v mut self, - annotation: A, - column: Column, - offset: usize, - to: V, - ) -> Result, Error> - where - V: Fn() -> Value + 'v, - for<'vr> Assigned: From<&'vr VR>, - A: Fn() -> AR, - AR: Into, - { - self.region.assign_fixed(annotation, column, offset, &to) + pub(crate) fn disable_description(&mut self) { + self.disable_description = true; } - pub fn get_fixed(&self, _row_index: usize, _column_index: usize, _rotation: Rotation) -> F { - unimplemented!("fixed column"); + pub(crate) fn is_descr_disabled(&self) -> bool { + self.disable_description } - // StoreExpression 里面调,拿 F 出去 evaluate - pub fn get_advice(&self, row_index: usize, column_index: usize, rotation: Rotation) -> F { - self.advice[column_index - self.width_start] - [(((row_index - self.height_start) as i32) + rotation.0) as usize] - } + /// Assign an advice column value (witness). + pub fn assign_advice<'v, V, VR, A, AR>( + &'v mut self, + annotation: A, + column: Column, + offset: usize, + to: V, + ) -> Result, Error> + where + V: Fn() -> Value + 'v, + for<'vr> Assigned: From<&'vr VR>, + A: Fn() -> AR, + AR: Into, + { + // Actually set the value + let res = self.region.assign_advice(annotation, column, offset, &to); + // Cache the value + // Note that the `value_field` in `AssignedCell` might be `Value::unkonwn` if + // the column has different phase than current one, so we call to `to` + // again here to cache the value. + if res.is_ok() { + to().map(|f: VR| { + self.advice.insert((column.index(), offset), Assigned::from(&f).evaluate()); + }); + } + res + } - pub fn challenges(&self) -> &S { - self.challenges + pub fn assign_fixed<'v, V, VR, A, AR>( + &'v mut self, + annotation: A, + column: Column, + offset: usize, + to: V, + ) -> Result, Error> + where + V: Fn() -> Value + 'v, + for<'vr> Assigned: From<&'vr VR>, + A: Fn() -> AR, + AR: Into, + { + self.region.assign_fixed(annotation, column, offset, &to) + } + + pub fn get_fixed(&self, _row_index: usize, _column_index: usize, _rotation: Rotation) -> F { + unimplemented!("fixed column"); + } + + // StoreExpression 里面调,拿 F 出去 evaluate + pub fn get_advice(&self, row_index: usize, column_index: usize, rotation: Rotation) -> F { + self.advice.get(&(column_index, row_index + rotation.0 as usize)) + .expect("Advice not found") + .clone() + } + + pub fn challenges(&self) -> &S { + self.challenges + } + + + // pub fn word_rlc(&self, n: U256) -> Value { + // self.challenges + // .evm_word() + // .map(|r| rlc::value(&n.to_le_bytes(), r)) + // } + // pub fn empty_code_hash_rlc(&self) -> Value { + // self.word_rlc(CodeDB::empty_code_hash().to_word()) + // } + + + /// Constrains a cell to have a constant value. + /// + /// Returns an error if the cell is in a column where equality has not been + /// enabled. + pub fn constrain_constant( + &mut self, + cell: AssignedCell, + constant: VR, + ) -> Result<(), Error> + where + VR: Into>, + { + self.region.constrain_constant(cell.cell(), constant.into()) + } } - // pub fn word_rlc(&self, n: U256) -> Value { - // self.challenges - // .evm_word() - // .map(|r| rlc::value(&n.to_le_bytes(), r)) - // } - // pub fn empty_code_hash_rlc(&self) -> Value { - // self.word_rlc(CodeDB::empty_code_hash().to_word()) - // } - - - /// Constrains a cell to have a constant value. - /// - /// Returns an error if the cell is in a column where equality has not been - /// enabled. - pub fn constrain_constant( - &mut self, - cell: AssignedCell, - constant: VR, - ) -> Result<(), Error> - where - VR: Into>, - { - self.region.constrain_constant(cell.cell(), constant.into()) - } -} - #[derive(Debug, Clone)] pub struct StoredExpression { pub(crate) name: String, - cell: Cell, - cell_type: C, - expr: Expression, - expr_id: String, + pub(crate) cell: Cell, + pub(crate) cell_type: C, + pub(crate) expr: Expression, + pub(crate) expr_id: String, } impl Hash for StoredExpression { diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index 7c3c992c64..bba8f6250a 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -11,6 +11,7 @@ use halo2_proofs::{ poly::Rotation, }; use halo2_proofs::arithmetic::FieldExt; +use std::cell; use std::collections::{BTreeMap, HashMap}; use std::fmt::Debug; use std::hash::Hash; @@ -122,6 +123,14 @@ impl CellTypeTrait for EvmCellType { fn byte_type() -> Option { Some(EvmCellType::LookupByte) } + + fn storage_for_phase(phase: u8) -> Self { + match phase { + 0 => EvmCellType::StoragePhase1, + 1 => EvmCellType::StoragePhase2, + _ => unreachable!(), + } + } } #[derive(Clone, Debug)] @@ -164,9 +173,30 @@ impl CellConfig { pub trait CellTypeTrait: - Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash + Default { - fn byte_type() -> Option; + Clone + Copy + Debug + PartialEq + Eq + PartialOrd + Ord + Hash + Default +{ + fn byte_type() -> Option; + + // The phase that given `Expression` becomes evaluateable. + fn expr_phase(expr: &Expression) -> u8 { + use Expression::*; + match expr { + Challenge(challenge) => challenge.phase() + 1, + Advice(query) => query.phase(), + Constant(_) | Selector(_) | Fixed(_) | Instance(_) => 0, + Negated(a) | Expression::Scaled(a, _) => Self::expr_phase(a), + Sum(a, b) | Product(a, b) => std::cmp::max(Self::expr_phase(a), Self::expr_phase(b)), + } + } + + /// Return the storage phase of phase + fn storage_for_phase(phase: u8) -> Self; + + /// Return the storage cell of the expression + fn storage_for_expr(expr: &Expression) -> Self { + Self::storage_for_phase(Self::expr_phase::(expr)) } +} @@ -175,6 +205,7 @@ pub trait CellTypeTrait: #[derive(Clone, Debug)] pub(crate) struct CellColumn_ { + column: Column, index: usize, cell_type: C, height: usize, @@ -220,18 +251,21 @@ impl CellManager_ { }); }; + println!("\nInitiating cm:"); cell_configs .iter() .for_each(|c| { let cols = c.init_columns(meta); let mut cell_list = Vec::with_capacity(cols.len() * max_height); query_expression(meta, |meta| { + println!("cols.len() init {} * {}", cols.len(), max_height); for w in 0..cols.len() { for h in 0..max_height { let cell: Cell<_> = Cell::new(meta, cols[w], offset + h); cell_list.push(cell); } cell_columns.push(CellColumn_ { + column: cols[w], index: w, cell_type: c.cell_type, height: 0, @@ -239,13 +273,11 @@ impl CellManager_ { }); } }); - cells.insert(c.cell_type, (total_width, cell_list)); + cells.insert(c.cell_type, (total_width, cell_list.clone())); + println!("cell type {:?} start with {} for window {}, cell_list {}", c.cell_type, total_width, c.num_columns, cell_list.len()); total_width += cols.len(); }); - println!("______________\n"); - cells.keys().for_each(|k| println!("cell type: {:?}, start_width: {:?}, #cells: {:?}\n", - k, cells.get(k).unwrap().0, cells.get(k).unwrap().1)); Self { cells, cell_configs, @@ -256,6 +288,13 @@ impl CellManager_ { } } + pub(crate) fn get_columns(&self) -> Vec> { + self.columns + .iter() + .map(|c| c.column.clone()) + .collect() + } + pub(crate) fn get_width(&self) -> usize { self.total_width } @@ -269,23 +308,32 @@ impl CellManager_ { } pub(crate) fn set_max_height(&mut self, meta: &mut VirtualCells, max_height: usize) { - if max_height > self.max_height { - self.cells.values_mut() - .enumerate() - .for_each(|(_, (_, cells))| { - let col = cells[0].column(); - let mut added_cells = (self.max_height..max_height) - .map(|h| Cell::new(meta, col, self.offset + h)) - .collect::>(); - cells.append(&mut added_cells); + let mut new_cells = HashMap::new(); + self.cells + .iter() + .for_each(|(cell_type, (start_width, cells))| { + let window = self.get_config(*cell_type).num_columns; + let mut tmp = Vec::with_capacity(window * max_height); + for w in 0..window { + if max_height < self.max_height { + println!("\n-- set_max_height: {} -> {}", self.max_height, max_height); + tmp.extend_from_slice(&cells[w * self.max_height..w * self.max_height + max_height]); + } else { + println!("\n++ set_max_height: {} -> {}", self.max_height, max_height); + tmp.extend_from_slice(&cells[w * self.max_height..w * self.max_height + self.max_height]); + print!(" tmp.len() {} -> ", tmp.len()); + let col = tmp.last().unwrap().column(); + tmp.extend( + (self.max_height..max_height) + .map(|h| Cell::new(meta, col, self.offset + h)) + ); + print!("{} ", tmp.len()); + } } - ); - } else { - self.cells - .values_mut() - .enumerate() - .for_each(|(_, (_, cells))| cells.truncate(max_height)); - } + println!("added cells for {:?} to {}", cell_type, tmp.len()); + new_cells.insert(*cell_type, (*start_width, tmp)); + }); + self.cells = new_cells; self.max_height = max_height; } @@ -319,18 +367,32 @@ impl CellManager_ { pub(crate) fn query_cells(&mut self, cell_type: C, count: usize) -> Vec> { let mut targets = Vec::with_capacity(count); - let (start_width, cell_list) = self.cells.get(&cell_type).expect("Cell type not found"); - let window = self.get_config(cell_type).num_columns; + let (start_width, cell_list) = self.cells + .get(&cell_type) + .expect(&format!("Cell type {:?} not found", cell_type)); + let window = self.get_config(cell_type).num_columns; + + println!("querying {:?} {} cells", cell_type, count); + + if cell_list.len() == 2 || cell_list.len() == 21 { + println!("\n fucked up place, start_width {} window {}", start_width, window); + self.cells + .iter() + .for_each(|(c, (start, l))| print!("{:?}: {} |", c, l.len()) ); + + // println!( + // "columns {:?}", self.columns[*start_width..start_width + window].to_vec() + // ) + } + - println!("cell_type {:?} get {:?}", cell_type, start_width); - println!("{:?}", self.cell_configs); - - while targets.len() < count { // Search best cell in window of columns designated for this CellType - let c = self.next_column(cell_type, &self.columns[*start_width..start_width + window]); - targets.push(cell_list[c.index * self.max_height + c.height].clone()); + let (index, height) = self.next_column(cell_type, &self.columns[*start_width..start_width + window]); + targets.push(cell_list[index * self.max_height + height].clone()); + // println!("at ({} * {} + {})", index, self.max_height, height); + self.columns[start_width + index].height += 1; } targets } @@ -339,23 +401,23 @@ impl CellManager_ { self.query_cells(cell_type, 1)[0].clone() } - fn next_column(&self, cell_type: C, columns: &[CellColumn_]) -> CellColumn_ { - let mut best_col: Option> = None; + fn next_column(&self, cell_type: C, columns: &[CellColumn_]) -> (usize, usize) { + let mut best_pos: Option<(usize, usize)> = None; let mut best_height = self.max_height; for column in columns.iter() { assert!(column.cell_type == cell_type); if column.height < best_height { - best_col = Some(column.clone()); + best_pos = Some((column.index, column.height)); best_height = column.height; } } - match best_col { - Some(col) => col, + println!("best pos: {:?}", best_pos); + match best_pos { + Some(pos) => pos, // If we reach this case, it means that all the columns of cell_type have assignments // taking self.height rows, so there's no more space. None => panic!("not enough cells for query: {:?}", cell_type), } } - } diff --git a/zkevm-circuits/src/circuit_tools/constraint_builder.rs b/zkevm-circuits/src/circuit_tools/constraint_builder.rs index 5ad2423c66..24ea3868ec 100644 --- a/zkevm-circuits/src/circuit_tools/constraint_builder.rs +++ b/zkevm-circuits/src/circuit_tools/constraint_builder.rs @@ -7,7 +7,7 @@ use gadgets::util::{and, sum, Scalar}; use halo2_proofs::plonk::{ConstraintSystem, Expression}; use itertools::Itertools; -use super::cell_manager::{Cell, CellManager_, CellTypeTrait, EvmCellType}; +use super::{cell_manager::{Cell, CellManager_, CellTypeTrait, EvmCellType}, cached_region::StoredExpression}; /// Lookup data #[derive(Clone)] @@ -25,7 +25,9 @@ pub struct LookupData { /// Constraint builder #[derive(Clone)] pub struct ConstraintBuilder { + /// Constraints to be returned to meta constraints: Vec<(&'static str, Expression)>, + /// Max degree of constraints max_degree: usize, conditions: Vec>, /// The lookups @@ -34,6 +36,10 @@ pub struct ConstraintBuilder { pub lookup_tables: Vec>, /// CellManager pub cell_manager: Option>, + /// Disable macro-generated description for constraints & lookups + pub disable_description: bool, + /// Intermediate expression to split high-degree constraints + pub stored_expressions: Vec>, } impl ConstraintBuilder { @@ -45,13 +51,24 @@ impl ConstraintBuilder { lookups: Vec::new(), lookup_tables: Vec::new(), cell_manager, + disable_description: false, + stored_expressions: Vec::new(), } } pub(crate) fn set_cell_manager(&mut self, cell_manager: CellManager_) { + println!("set_cell_manager!!"); self.cell_manager = Some(cell_manager); } + pub(crate) fn disable_description(&mut self) { + self.disable_description = true; + } + + pub(crate) fn is_descr_disabled(&self) -> bool { + self.disable_description + } + pub(crate) fn require_zero(&mut self, name: &'static str, constraint: Expression) { self.add_constraint(name, constraint); } @@ -164,7 +181,6 @@ impl ConstraintBuilder { } pub(crate) fn generate_constraints(&self) -> Vec<(&'static str, Expression)> { - // 这里没有 self.constraints.clone() } @@ -310,6 +326,97 @@ impl ConstraintBuilder { ); } + pub(crate) fn store_expression( + &mut self, + name: &str, + expr: Expression, + cell_type: C, + ) -> Expression { + // Check if we already stored the expression somewhere + let stored_expression = self.find_stored_expression(&expr, cell_type); + + match stored_expression { + Some(stored_expression) => { + stored_expression.cell.expr() + } + None => { + // Require the stored value to equal the value of the expression + let cell = self.query_one(cell_type); + let name = format!("{} (stored expression)", name); + self.add_constraint( + Box::leak(name.clone().into_boxed_str()), + cell.expr() - expr.clone(), + ); + + self.stored_expressions.push(StoredExpression { + name, + cell: cell.clone(), + cell_type, + expr_id: expr.identifier(), + expr, + }); + cell.expr() + } + } + } + + pub(crate) fn find_stored_expression( + &self, + expr: &Expression, + cell_type: C, + ) -> Option<&StoredExpression> { + let expr_id = expr.identifier(); + self.stored_expressions + .iter() + .find(|&e| e.cell_type == cell_type && e.expr_id == expr_id) + } + + fn split_expression( + &mut self, + name: &'static str, + expr: Expression, + max_degree: usize, + ) -> Expression { + if expr.degree() > max_degree { + match expr { + Expression::Negated(poly) => { + Expression::Negated(Box::new(self.split_expression(name, *poly, max_degree))) + } + Expression::Scaled(poly, v) => { + Expression::Scaled(Box::new(self.split_expression(name, *poly, max_degree)), v) + } + Expression::Sum(a, b) => { + let a = self.split_expression(name, *a, max_degree); + let b = self.split_expression(name, *b, max_degree); + a + b + } + Expression::Product(a, b) => { + let (mut a, mut b) = (*a, *b); + while a.degree() + b.degree() > max_degree { + let mut split = |expr: Expression| { + if expr.degree() > max_degree { + self.split_expression(name, expr, max_degree) + } else { + let cell_type = C::storage_for_expr(&expr); + self.store_expression(name, expr, cell_type) + } + }; + if a.degree() >= b.degree() { + a = split(a); + } else { + b = split(b); + } + } + a * b + } + _ => expr.clone(), + } + } else { + expr.clone() + } + } + + pub(crate) fn print_stats(&self) { let mut expressions = self.constraints.clone(); expressions.sort_by(|a, b| a.1.degree().cmp(&b.1.degree())); @@ -637,7 +744,6 @@ impl, I: IntoIterator> RLCChainableValue { - let description = $crate::concat_with_preamble!( - stringify!($($lhs)*), - " == ", - stringify!($($rhs)*) - ); + let description = match $cb.is_descr_disabled() { + true => $crate::concat_with_preamble!( + stringify!($($lhs)*), + " == ", + stringify!($($rhs)*) + ), + false => "" + }; $crate::_require!($cb, description, $($lhs)* => $($rhs)*) }; @@ -683,7 +792,7 @@ macro_rules! _require2 { #[macro_export] macro_rules! _cb { () => {{ - ConstraintBuilder::::new(0, None) + ConstraintBuilder::::new(0, None) }}; } @@ -707,13 +816,16 @@ macro_rules! concat_with_preamble { #[macro_export] macro_rules! _unreachablex { ($cb:expr $(,$descr:expr)?) => {{ - let descr = concat_with_preamble!( - "unreachable executed", - $( - ": ", - $descr, - )* - ); + let descr = match $cb.is_descr_disabled() { + true => concat_with_preamble!( + "unreachable executed", + $( + ": ", + $descr, + )* + ), + false => "", + }; _require!($cb, descr, true => false) }}; } @@ -722,22 +834,26 @@ macro_rules! _unreachablex { #[macro_export] macro_rules! _require { ($cb:expr, $lhs:expr => bool) => {{ - $cb.require_boolean( - concat_with_preamble!( + let description = match $cb.is_descr_disabled() { + true => concat_with_preamble!( stringify!($lhs), " => ", "bool", ), - $lhs.expr(), - ); + false => "" + }; + $cb.require_boolean(description, $lhs.expr()); }}; ($cb:expr, $lhs:expr => $rhs:expr) => {{ - let description = concat_with_preamble!( - stringify!($lhs), - " => ", - stringify!($rhs) - ); + let description = match $cb.is_descr_disabled() { + true => concat_with_preamble!( + stringify!($lhs), + " => ", + stringify!($rhs) + ), + false => "" + }; _require!($cb, description, $lhs => $rhs) }}; @@ -760,8 +876,8 @@ macro_rules! _require { // Lookup using a tuple ($cb:expr, ($($v:expr),+) => @$tag:expr) => {{ - $cb.lookup( - concat_with_preamble!( + let description = match $cb.is_descr_disabled() { + true => concat_with_preamble!( "(", $( stringify!($v), @@ -770,6 +886,10 @@ macro_rules! _require { ") => @", stringify!($tag), ), + false => "" + }; + $cb.lookup( + description, $tag.to_string(), vec![$($v.expr(),)*], ); @@ -784,12 +904,16 @@ macro_rules! _require { // Lookup using an array ($cb:expr, $values:expr => @$tag:expr) => {{ - $cb.lookup( - concat_with_preamble!( + let description = match $cb.is_descr_disabled() { + true => concat_with_preamble!( stringify!($values), " => @", stringify!($tag), ), + false => "" + }; + $cb.lookup( + description, $tag.to_string(), $values.clone(), ); @@ -804,8 +928,8 @@ macro_rules! _require { // Put values in a lookup table using a tuple ($cb:expr, @$tag:expr => ($($v:expr),+)) => {{ - $cb.lookup_table( - concat_with_preamble!( + let description = match $cb.is_descr_disabled() { + true => concat_with_preamble!( "@", stringify!($tag), " => (", @@ -815,20 +939,28 @@ macro_rules! _require { )* ")", ), + false => "", + }; + $cb.lookup_table( + description, $tag.to_string(), vec![$($v.expr(),)*], ); }}; // Put values in a lookup table using an array ($cb:expr, @$tag:expr => $values:expr) => {{ - $cb.lookup_table( - concat_with_preamble!( + let description = match $cb.is_descr_disabled() { + true => concat_with_preamble!( "@", stringify!($tag), " => (", stringify!($values), ")", ), + false => "", + }; + $cb.lookup_table( + description, $tag.to_string(), $values, ); @@ -930,17 +1062,27 @@ macro_rules! matchw { macro_rules! assign { // Column ($region:expr, ($column:expr, $offset:expr) => $value:expr) => {{ - use halo2_proofs::circuit::Value; - let description = - $crate::concat_with_preamble!(stringify!($column), " => ", stringify!($value)); + use halo2_proofs::circuit::Value; + let description = match $region.is_descr_disabled() { + true => $crate::concat_with_preamble!(stringify!($column), " => ", stringify!($value)), + false => "" + }; let value: F = $value; $region.assign_advice(|| description, $column, $offset, || Value::known(value)) }}; + ($region:expr, ($column:expr, $offset:expr) => $annotation:expr, $value:expr) => {{ + use halo2_proofs::circuit::Value; + let value: F = $value; + $region.name_column(|| $annotation, $column); + $region.assign_advice(|| "", $column, $offset, || Value::known(value)) + }}; // Cell ($region:expr, $cell:expr, $offset:expr => $value:expr) => {{ use halo2_proofs::circuit::Value; - let description = - $crate::concat_with_preamble!(stringify!($cell), " => ", stringify!($value)); + let description = match $region.is_descr_disabled() { + true => $crate::concat_with_preamble!(stringify!($cell), " => ", stringify!($value)), + false => "" + }; let value: F = $value; $region.assign_advice( || description, @@ -949,6 +1091,16 @@ macro_rules! assign { || Value::known(value), ) }}; + ($region:expr, $cell:expr, $offset:expr => $annotation:expr, $value:expr) => {{ + use halo2_proofs::circuit::Value; + let value: F = $value; + $region.assign_advice( + || $annotation, + $cell.column(), + $offset + $cell.rotation(), + || Value::known(value), + ) + }}; } /// assign fixed diff --git a/zkevm-circuits/src/circuit_tools/memory.rs b/zkevm-circuits/src/circuit_tools/memory.rs index cd157164b2..d2d94869c4 100644 --- a/zkevm-circuits/src/circuit_tools/memory.rs +++ b/zkevm-circuits/src/circuit_tools/memory.rs @@ -55,6 +55,10 @@ impl Memory { unreachable!() } + pub(crate) fn get_columns(&self) -> Vec> { + self.columns.clone() + } + pub(crate) fn generate_constraints( &self, cb: &mut ConstraintBuilder, diff --git a/zkevm-circuits/src/circuit_tools/tests/util.rs b/zkevm-circuits/src/circuit_tools/tests/util.rs index 4c15a43fe9..086d16370d 100644 --- a/zkevm-circuits/src/circuit_tools/tests/util.rs +++ b/zkevm-circuits/src/circuit_tools/tests/util.rs @@ -6,7 +6,7 @@ use crate::circuit_tools::cell_manager::{Cell, CellManager_, CellTypeTrait}; use crate::circuit_tools::constraint_builder::ConstraintBuilder; use crate::circuit_tools::memory::Memory; use crate::util::{Expr, query_expression}; -use crate::circuit_tools::{table::LookupTable_, cached_region::CachedRegion}; +use crate::circuit_tools::{table::LookupTable_, cached_region::{CachedRegion, MacroDescr}}; use eth_types::Field; use gadgets::util::Scalar; @@ -56,6 +56,14 @@ impl CellTypeTrait for CellType { fn byte_type() -> Option { Some(CellType::PhaseOne) } + + fn storage_for_phase(phase: u8) -> Self { + match phase { + 0 => CellType::PhaseOne, + 1 => CellType::PhaseTwo, + _ => unreachable!(), + } + } } impl LookupTable_ for TestTable { @@ -176,7 +184,7 @@ impl TestConfig { // We query it once during synthesis and // make it accessable across Config through CachedRegion. let challenges = [r1]; - let mut cached_region = cached_region::CachedRegion::new(&mut region, &challenges, self.cell_columns.clone(), REGION_HEIGHT, 0); + let mut cached_region = cached_region::CachedRegion::new(&mut region, &challenges); self.cell_gadget.assign(&mut cached_region, 0) }, ) diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 2fbaf8f0f7..e26b43757a 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -33,7 +33,7 @@ use crate::{ assign, assignf, circuit, circuit_tools::{ memory::Memory, - cached_region::CachedRegion, + cached_region::{CachedRegion, MacroDescr}, }, mpt_circuit::{ helpers::{main_memory, parent_memory, MPTConstraintBuilder, MainRLPGadget}, @@ -126,7 +126,7 @@ pub struct MPTConfig { pub(crate) q_last: Column, pub(crate) rows_left_in_state: Column, pub(crate) rlp_columns: Vec>, - pub(crate) managed_columns: Vec>, + pub(crate) state_columns: Vec>, pub(crate) memory: Memory, keccak_table: KeccakTable, fixed_table: [Column; 3], @@ -134,7 +134,7 @@ pub struct MPTConfig { state_machine: StateMachineConfig, pub(crate) mpt_table: MptTable, cb: MPTConstraintBuilder, -} +} /// Enumerator to determine the type of row in the fixed table. #[derive(Clone, Copy, Debug)] @@ -166,7 +166,6 @@ impl MPTState { Self { r, memory: memory.clone(), - ..Default::default() } } } @@ -191,8 +190,6 @@ impl MPTConfig { .try_into() .unwrap(); - let rlp_columns = (0..50).map(|_| meta.advice_column()).collect::>(); - let managed_columns = (0..15).map(|_| meta.advice_column()).collect::>(); let memory_columns = (0..5).map(|_| meta.advice_column()).collect::>(); let mut state_machine = StateMachineConfig::construct(meta); @@ -213,40 +210,44 @@ impl MPTConfig { memory: memory.clone(), }; - let mut cm = CellManager_::new( + + let rlp_cm = CellManager_::new( + meta, + // Type, #cols, phase, permutable + vec![(EvmCellType::StoragePhase1, 50, 0, false)], + Vec::new(), + 0, + 1 + ); + let rlp_columns = rlp_cm.get_columns(); + let state_cm = CellManager_::new( meta, + // Type, #cols, phase, permutable vec![ - (EvmCellType::StoragePhase1, 10, 0, false), - (EvmCellType::StoragePhase2, 10, 1, false), - (EvmCellType::LookupByte, 32, 0, false), + (EvmCellType::StoragePhase1, 15, 0, false), + (EvmCellType::LookupByte, 5, 0, false) ], - // no need to pass in fixed table since it's StoragePhase1 - vec![&keccak_table], + Vec::new(), 0, - 32 + 1 ); - let mut cb = MPTConstraintBuilder::new(33 + 10, Some(cm)); + let state_columns = state_cm.get_columns(); + let mut cb = MPTConstraintBuilder::new(33 + 10, None); meta.create_gate("MPT", |meta| { - circuit!([meta, cb.base], { + circuit!([meta, cb], { // Populate lookup tables require!(@"keccak" => >::advice_columns(&keccak_table).iter().map(|table| a!(table)).collect()); require!(@"fixed" => fixed_table.iter().map(|table| f!(table)).collect()); ifx!{f!(q_enable) => { // RLP item decoding unit - // let mut cell_manager = CellManager::new(meta, 1, &rlp_columns, 0); - // cell_manager.reset(1); - // cb.base.set_cell_manager(cell_manager); + cb.base.set_cell_manager(rlp_cm); rlp_item = MainRLPGadget::construct(&mut cb, &ctx.r); ctx.rlp_item = rlp_item.clone(); // Main MPT circuit - // let cell_manager = CellManager::new(meta, &managed_columns); - // cb.base.set_cell_manager(cell_manager); - // State machine - // TODO(Brecht): state machine constraints - // Always start and end with the start state + cb.base.set_cell_manager(state_cm); ifx! {f!(q_first) + f!(q_last) => { require!(a!(state_machine.is_start) => true); }}; @@ -321,7 +322,6 @@ impl MPTConfig { println!("num lookups: {}", meta.lookups().len()); println!("num advices: {}", meta.num_advice_columns()); println!("num fixed: {}", meta.num_fixed_columns()); - // cb.base.print_stats(); MPTConfig { q_enable, @@ -329,7 +329,7 @@ impl MPTConfig { q_last, rows_left_in_state, rlp_columns, - managed_columns, + state_columns, memory, keccak_table, fixed_table, @@ -366,10 +366,7 @@ impl MPTConfig { let mut rlp_values = Vec::new(); let mut cahced_region = CachedRegion::new( &mut region, - challenges, - self.managed_columns.clone(), - node.values.len(), - offset + challenges ); // Decompose RLP for (idx, bytes) in node.values.iter().enumerate() { @@ -386,19 +383,14 @@ impl MPTConfig { assignf!(cahced_region, (self.rows_left_in_state, offset + idx) => (node.values.len() - idx).scalar())?; } + // Assign nodes if node.start.is_some() { // println!("{}: start", offset); - let mut cahced_region = CachedRegion::new( + assign!(region, (self.state_machine.is_start, offset) => "is_start", true.scalar())?; + self.state_machine.start_config.assign( &mut region, challenges, - self.managed_columns.clone(), - StartRowType::Count as usize, - offset - ); - assign!(cahced_region, (self.state_machine.is_start, offset) => true.scalar())?; - self.state_machine.start_config.assign( - &mut cahced_region, self, &mut pv, offset, @@ -407,16 +399,10 @@ impl MPTConfig { )?; } else if node.extension_branch.is_some() { // println!("{}: branch", offset); - let mut cahced_region = CachedRegion::new( + assign!(region, (self.state_machine.is_branch, offset) => "is_branch", true.scalar())?; + self.state_machine.branch_config.assign( &mut region, challenges, - self.managed_columns.clone(), - ExtensionBranchRowType::Count as usize, - offset - ); - assign!(cahced_region, (self.state_machine.is_branch, offset) => true.scalar())?; - self.state_machine.branch_config.assign( - &mut cahced_region, self, &mut pv, offset, @@ -425,16 +411,10 @@ impl MPTConfig { )?; } else if node.storage.is_some() { // println!("{}: storage", offset); - let mut cahced_region = CachedRegion::new( + assign!(region, (self.state_machine.is_storage, offset) => "is_storage", true.scalar())?; + self.state_machine.storage_config.assign( &mut region, challenges, - self.managed_columns.clone(), - StorageRowType::Count as usize, - offset - ); - assign!(cahced_region, (self.state_machine.is_storage, offset) => true.scalar())?; - self.state_machine.storage_config.assign( - &mut cahced_region, self, &mut pv, offset, @@ -443,16 +423,10 @@ impl MPTConfig { )?; } else if node.account.is_some() { // println!("{}: account", offset); - let mut cahced_region = CachedRegion::new( + assign!(region, (self.state_machine.is_account, offset) => "is_account", true.scalar())?; + self.state_machine.account_config.assign( &mut region, challenges, - self.managed_columns.clone(), - AccountRowType::Count as usize, - offset - ); - assign!(cahced_region, (self.state_machine.is_account, offset) => true.scalar())?; - self.state_machine.account_config.assign( - &mut cahced_region, self, &mut pv, offset, @@ -672,7 +646,7 @@ mod tests { }; println!("{} {:?}", idx, path); - // let prover = MockProver::run(9, &circuit, vec![pub_root]).unwrap(); + // let prover = MockProver::run(9, &circuit, vec![pube45_root]).unwrap(); let prover = MockProver::run(14 /* 9 */, &circuit, vec![]).unwrap(); assert_eq!(prover.verify_at_rows(0..num_rows, 0..num_rows,), Ok(())); // assert_eq!(prover.verify_par(), Ok(())); @@ -684,24 +658,6 @@ mod tests { #[test] fn graph_mpt() { use plotters::prelude::*; - - // let path = "src/mpt_circuit/tests"; - // let files = fs::read_dir(path).unwrap(); - // let files: Vec = files - // .filter_map(Result::ok) - // .filter(|d| { - // if let Some(e) = d.path().extension() { - // e == "json" - // } else { - // false - // } - // }).collect(); - - // let path = &files[0].path(); - // let mut parts = path.to_str().unwrap().split('-'); - // parts.next(); - // let file = std::fs::File::open(path.clone()); - // let reader = std::io::BufReader::new(file.unwrap()); let w: Vec> = serde_json::from_str(debug_file).unwrap(); let randomness: Fr = 2.scalar(); @@ -727,11 +683,12 @@ mod tests { println!("Start graphing"); - let root = BitMapBackend::new("mpt-chip-layout.png", (2048, 7680)).into_drawing_area(); + let root = BitMapBackend::new("mpt-chip-layout1.png", (2048, 7680)).into_drawing_area(); root.fill(&WHITE).unwrap(); let root = root.titled("MPT Chip Layout", ("sans-serif", 60)).unwrap(); halo2_proofs::dev::CircuitLayout::default() + .show_column_names(true) .render(9, &circuit, &root) .unwrap(); @@ -743,4 +700,4 @@ mod tests { } } -const debug_file: &'static str = "[[1,0,1,0,248,81,0,248,81,0,3,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,160,12,238,76,188,132,183,202,253,232,24,203,94,245,16,89,89,51,190,136,196,16,141,191,3,32,223,60,175,134,134,252,108,0,160,12,238,76,188,132,183,202,253,232,24,203,94,245,16,89,89,51,190,136,196,16,141,191,3,32,223,60,175,134,134,252,108,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,160,174,121,120,114,157,43,164,140,103,235,28,242,186,33,76,152,157,197,109,149,229,229,22,189,233,207,92,195,82,121,240,3,0,160,174,121,120,114,157,43,164,140,103,235,28,242,186,33,76,152,157,197,109,149,229,229,22,189,233,207,92,195,82,121,240,3,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],[226,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,165,122,171,104,113,212,176,43,65,48,207,251,142,53,47,186,90,181,22,93,66,192,18,250,18,108,20,25,228,62,211,52,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,165,122,171,104,113,212,176,43,65,48,207,251,142,53,47,186,90,181,22,93,66,192,18,250,18,108,20,25,228,62,211,52,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,17],[248,105,160,32,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,6],[248,105,160,32,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,4],[0,0,160,32,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,18],[184,70,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,68,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,7],[184,70,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,68,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,8],[0,160,86,232,31,23,27,204,85,166,255,131,69,230,146,192,248,110,91,72,224,27,153,108,173,192,1,98,47,181,227,99,180,33,0,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,9],[0,160,86,232,31,23,27,204,85,166,255,131,69,230,146,192,248,110,91,72,224,27,153,108,173,192,1,98,47,181,227,99,180,33,0,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,11],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,90,149,210,63,96,21,90,79,215,113,54,179,202,200,190,125,138,153,12,147,10,164,5,127,203,30,243,148,15,111,49,120,131,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,10],[226,24,160,165,122,171,104,113,212,176,43,65,48,207,251,142,53,47,186,90,181,22,93,66,192,18,250,18,108,20,25,228,62,211,52,5],[226,24,160,165,122,171,104,113,212,176,43,65,48,207,251,142,53,47,186,90,181,22,93,66,192,18,250,18,108,20,25,228,62,211,52,5],[248,81,128,128,128,160,12,238,76,188,132,183,202,253,232,24,203,94,245,16,89,89,51,190,136,196,16,141,191,3,32,223,60,175,134,134,252,108,128,128,128,128,128,160,174,121,120,114,157,43,164,140,103,235,28,242,186,33,76,152,157,197,109,149,229,229,22,189,233,207,92,195,82,121,240,3,128,128,128,128,128,128,128,5],[248,81,128,128,128,160,12,238,76,188,132,183,202,253,232,24,203,94,245,16,89,89,51,190,136,196,16,141,191,3,32,223,60,175,134,134,252,108,128,128,128,128,128,160,174,121,120,114,157,43,164,140,103,235,28,242,186,33,76,152,157,197,109,149,229,229,22,189,233,207,92,195,82,121,240,3,128,128,128,128,128,128,128,5],[248,105,160,32,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,184,70,248,68,128,128,160,86,232,31,23,27,204,85,166,255,131,69,230,146,192,248,110,91,72,224,27,153,108,173,192,1,98,47,181,227,99,180,33,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,5],[248,105,160,32,183,32,52,38,131,211,211,218,246,83,140,45,89,109,3,231,97,202,248,167,7,116,197,134,209,86,108,48,129,43,150,184,70,248,68,128,128,160,86,232,31,23,27,204,85,166,255,131,69,230,146,192,248,110,91,72,224,27,153,108,173,192,1,98,47,181,227,99,180,33,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,5]]"; \ No newline at end of file +const debug_file: &'static str = "[[0,1,0,1,249,2,17,249,2,17,13,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0],[0,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,0,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,0,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,0,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,0,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,0,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,0,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,0,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,0,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,0,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,0,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,0,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,0,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,0,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,198,110,59,110,207,162,15,138,151,80,193,238,182,30,35,42,168,192,180,204,238,61,99,82,32,113,75,76,38,31,245,168,0,160,208,11,7,160,57,118,105,130,12,148,160,224,101,79,108,119,75,73,27,251,23,112,202,194,98,232,67,35,41,20,109,227,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,0,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,0,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,17],[0,1,0,1,249,2,17,249,2,17,14,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,0,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,0,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,0,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,0,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,0,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,0,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,0,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,0,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,0,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,0,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,0,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,0,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,0,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,0,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,66,160,223,51,184,103,51,48,79,182,55,124,160,55,136,72,34,106,234,196,136,142,67,163,253,247,97,56,227,113,81,112,0,160,156,207,34,126,96,200,143,86,98,67,48,239,210,146,94,107,198,11,34,45,151,240,146,143,132,124,18,87,19,78,100,125,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,0,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,7,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,0,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,0,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,0,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,0,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,0,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,0,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,0,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,68,171,218,249,64,4,214,12,108,176,191,110,229,129,30,147,162,111,141,248,90,65,72,139,199,122,223,7,22,19,86,170,0,160,139,236,208,88,153,113,82,137,105,145,232,206,194,251,94,134,60,159,209,170,140,223,189,13,150,246,4,251,15,48,51,104,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,0,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,0,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,0,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,0,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,0,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,0,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,0,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,0,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,8,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,0,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,0,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,0,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,0,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,0,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,0,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,0,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,0,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,154,52,165,162,92,151,34,100,231,147,116,21,226,254,143,170,231,209,154,231,199,183,20,105,49,183,6,201,128,11,16,232,0,160,159,130,229,165,212,147,78,44,146,124,254,74,180,62,107,231,41,115,95,72,27,6,25,183,104,151,116,137,84,204,53,189,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,0,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,0,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,0,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,0,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,0,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,0,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,0,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,15,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,0,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,0,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,0,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,0,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,0,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,0,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,0,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,0,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,0,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,0,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,0,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,0,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,0,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,0,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,0,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,22,113,109,16,155,122,184,254,94,185,37,39,88,26,221,148,248,80,144,115,38,194,220,122,155,21,126,51,253,15,25,20,0,160,225,182,145,67,235,152,171,67,1,124,207,170,15,83,123,246,240,168,176,148,142,233,231,8,186,38,93,151,133,95,66,9,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,6,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,0,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,0,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,0,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,0,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,0,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,0,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,11,120,10,14,41,255,61,142,177,254,63,196,64,224,0,14,143,46,191,103,0,192,46,198,195,173,64,251,173,35,142,148,0,160,238,209,87,174,135,247,247,71,46,224,121,112,26,122,57,36,89,211,219,49,155,106,201,99,199,252,111,215,11,255,165,213,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,0,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,0,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,0,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,0,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,0,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,0,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,0,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,0,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,0,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[1,0,1,0,248,145,0,248,145,0,11,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,0,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,0,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,179,70,158,11,10,104,224,123,16,42,214,158,131,156,64,4,235,80,104,2,138,182,25,228,205,151,223,171,105,234,236,173,0,160,165,116,158,139,247,254,49,170,68,15,91,162,161,62,160,6,249,129,106,178,2,115,9,14,142,62,53,170,127,136,53,246,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,0,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[1,0,1,0,248,81,0,248,81,0,8,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,0,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,41,122,139,195,252,11,85,53,122,170,39,172,8,39,29,83,69,64,178,138,199,190,231,92,223,125,154,186,235,120,104,102,0,160,74,22,132,110,223,6,51,194,83,209,210,85,189,59,23,107,148,190,32,50,163,100,142,104,242,185,109,43,71,122,110,67,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[1,0,1,0,248,81,0,248,81,0,12,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,0,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,119,112,103,117,121,255,157,192,83,91,44,31,253,43,105,59,219,129,193,146,21,133,101,43,236,205,229,86,87,91,66,252,0,160,141,100,78,113,237,145,113,89,70,14,78,206,48,14,80,218,70,221,199,79,174,60,220,107,96,144,43,18,51,135,218,126,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,6],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4],[0,0,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,18],[184,70,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,68,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,7],[184,70,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,68,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,8],[0,160,53,203,234,79,145,82,155,67,90,65,188,199,39,235,164,30,181,122,126,243,25,253,115,22,82,102,179,140,10,155,162,255,0,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,9],[0,160,188,110,180,112,46,228,183,149,153,213,233,172,60,165,192,142,95,173,66,254,53,126,194,240,94,145,108,77,127,201,225,185,0,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,11],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,10],[1,0,1,0,248,81,0,248,81,0,1,1,0,11,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,80,90,222,110,109,11,60,70,62,54,96,68,136,32,251,73,11,145,37,204,201,177,59,4,177,45,197,186,81,171,201,54,0,160,80,90,222,110,109,11,60,70,62,54,96,68,136,32,251,73,11,145,37,204,201,177,59,4,177,45,197,186,81,171,201,54,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,117,254,248,169,140,212,202,48,190,248,66,108,226,49,13,176,213,221,44,93,158,12,29,42,13,71,21,208,116,159,193,173,0,160,117,254,248,169,140,212,202,48,190,248,66,108,226,49,13,176,213,221,44,93,158,12,29,42,13,71,21,208,116,159,193,173,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[226,27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,217,126,56,112,222,29,194,80,17,187,144,67,169,202,198,186,147,107,226,126,75,125,32,62,50,189,225,43,23,89,132,168,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,217,126,56,112,222,29,194,80,17,187,144,67,169,202,198,186,147,107,226,126,75,125,32,62,50,189,225,43,23,89,132,168,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[227,161,32,187,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,2],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,13],[226,160,32,14,45,82,118,18,7,59,38,238,205,253,113,126,106,50,12,244,75,74,250,194,176,115,45,159,203,226,183,250,12,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3],[17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,14],[226,160,32,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,15],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,19],[249,2,17,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,160,198,110,59,110,207,162,15,138,151,80,193,238,182,30,35,42,168,192,180,204,238,61,99,82,32,113,75,76,38,31,245,168,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,128,5],[249,2,17,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,160,208,11,7,160,57,118,105,130,12,148,160,224,101,79,108,119,75,73,27,251,23,112,202,194,98,232,67,35,41,20,109,227,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,128,5],[249,2,17,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,160,66,160,223,51,184,103,51,48,79,182,55,124,160,55,136,72,34,106,234,196,136,142,67,163,253,247,97,56,227,113,81,112,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,128,5],[249,2,17,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,160,156,207,34,126,96,200,143,86,98,67,48,239,210,146,94,107,198,11,34,45,151,240,146,143,132,124,18,87,19,78,100,125,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,128,5],[249,2,17,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,160,68,171,218,249,64,4,214,12,108,176,191,110,229,129,30,147,162,111,141,248,90,65,72,139,199,122,223,7,22,19,86,170,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,128,5],[249,2,17,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,160,139,236,208,88,153,113,82,137,105,145,232,206,194,251,94,134,60,159,209,170,140,223,189,13,150,246,4,251,15,48,51,104,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,128,5],[249,2,17,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,160,154,52,165,162,92,151,34,100,231,147,116,21,226,254,143,170,231,209,154,231,199,183,20,105,49,183,6,201,128,11,16,232,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,128,5],[249,2,17,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,160,159,130,229,165,212,147,78,44,146,124,254,74,180,62,107,231,41,115,95,72,27,6,25,183,104,151,116,137,84,204,53,189,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,128,5],[249,2,17,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,160,22,113,109,16,155,122,184,254,94,185,37,39,88,26,221,148,248,80,144,115,38,194,220,122,155,21,126,51,253,15,25,20,128,5],[249,2,17,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,160,225,182,145,67,235,152,171,67,1,124,207,170,15,83,123,246,240,168,176,148,142,233,231,8,186,38,93,151,133,95,66,9,128,5],[249,2,17,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,160,11,120,10,14,41,255,61,142,177,254,63,196,64,224,0,14,143,46,191,103,0,192,46,198,195,173,64,251,173,35,142,148,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,128,5],[249,2,17,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,160,238,209,87,174,135,247,247,71,46,224,121,112,26,122,57,36,89,211,219,49,155,106,201,99,199,252,111,215,11,255,165,213,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,128,5],[248,145,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,128,128,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,128,128,128,128,128,128,128,160,179,70,158,11,10,104,224,123,16,42,214,158,131,156,64,4,235,80,104,2,138,182,25,228,205,151,223,171,105,234,236,173,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,128,128,128,128,5],[248,145,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,128,128,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,128,128,128,128,128,128,128,160,165,116,158,139,247,254,49,170,68,15,91,162,161,62,160,6,249,129,106,178,2,115,9,14,142,62,53,170,127,136,53,246,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,160,41,122,139,195,252,11,85,53,122,170,39,172,8,39,29,83,69,64,178,138,199,190,231,92,223,125,154,186,235,120,104,102,128,128,128,128,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,160,74,22,132,110,223,6,51,194,83,209,210,85,189,59,23,107,148,190,32,50,163,100,142,104,242,185,109,43,71,122,110,67,128,128,128,128,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,128,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,128,128,128,160,119,112,103,117,121,255,157,192,83,91,44,31,253,43,105,59,219,129,193,146,21,133,101,43,236,205,229,86,87,91,66,252,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,128,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,128,128,128,160,141,100,78,113,237,145,113,89,70,14,78,206,48,14,80,218,70,221,199,79,174,60,220,107,96,144,43,18,51,135,218,126,128,128,128,128,5],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,184,70,248,68,128,128,160,53,203,234,79,145,82,155,67,90,65,188,199,39,235,164,30,181,122,126,243,25,253,115,22,82,102,179,140,10,155,162,255,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,5],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,184,70,248,68,128,128,160,188,110,180,112,46,228,183,149,153,213,233,172,60,165,192,142,95,173,66,254,53,126,194,240,94,145,108,77,127,201,225,185,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,5],[226,27,160,217,126,56,112,222,29,194,80,17,187,144,67,169,202,198,186,147,107,226,126,75,125,32,62,50,189,225,43,23,89,132,168,5],[248,81,128,160,80,90,222,110,109,11,60,70,62,54,96,68,136,32,251,73,11,145,37,204,201,177,59,4,177,45,197,186,81,171,201,54,128,128,128,128,128,128,128,128,128,160,117,254,248,169,140,212,202,48,190,248,66,108,226,49,13,176,213,221,44,93,158,12,29,42,13,71,21,208,116,159,193,173,128,128,128,128,128,5],[227,161,32,187,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,1,5],[226,160,32,14,45,82,118,18,7,59,38,238,205,253,113,126,106,50,12,244,75,74,250,194,176,115,45,159,203,226,183,250,12,246,17,5],[226,160,32,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,1,5]]"; \ No newline at end of file diff --git a/zkevm-circuits/src/mpt_circuit/account_leaf.rs b/zkevm-circuits/src/mpt_circuit/account_leaf.rs index 2ee5f6b8fb..140484e04b 100644 --- a/zkevm-circuits/src/mpt_circuit/account_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/account_leaf.rs @@ -1,7 +1,7 @@ use eth_types::Field; use gadgets::util::{pow, Scalar}; use halo2_proofs::{ - circuit::{Value}, + circuit::{Value, Region}, plonk::{Error, VirtualCells}, poly::Rotation, }; @@ -360,13 +360,18 @@ impl AccountLeafConfig { pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, S>, - ctx: &MPTConfig, + region: &mut Region, + challenges: &S, + mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, node: &Node, rlp_values: &[RLPItemWitness], ) -> Result<(), Error> { + let mut region = CachedRegion::new( + region, + challenges + ); let account = &node.account.clone().unwrap(); let key_items = [ @@ -394,7 +399,7 @@ impl AccountLeafConfig { let main_data = self.main_data - .witness_load(region, offset, &pv.memory[main_memory()], 0)?; + .witness_load(&mut region, offset, &pv.memory[main_memory()], 0)?; // Key let mut key_rlc = vec![0.scalar(); 2]; @@ -409,39 +414,39 @@ impl AccountLeafConfig { .iter() .zip(account.value_rlp_bytes[is_s.idx()].iter()) { - cell.assign(region, offset, byte.scalar())?; + cell.assign(&mut region, offset, byte.scalar())?; } for (cell, byte) in self.value_list_rlp_bytes[is_s.idx()] .iter() .zip(account.value_list_rlp_bytes[is_s.idx()].iter()) { - cell.assign(region, offset, byte.scalar())?; + cell.assign(&mut region, offset, byte.scalar())?; } key_data[is_s.idx()] = self.key_data[is_s.idx()].witness_load( - region, + &mut region, offset, &mut pv.memory[key_memory(is_s)], 0, )?; parent_data[is_s.idx()] = self.parent_data[is_s.idx()].witness_load( - region, + &mut region, offset, &mut pv.memory[parent_memory(is_s)], 0, )?; self.is_in_empty_trie[is_s.idx()].assign( - region, + &mut region, offset, parent_data[is_s.idx()].rlc, pv.r, )?; let rlp_key_witness = self.rlp_key[is_s.idx()].assign( - region, + &mut region, offset, &account.list_rlp_bytes[is_s.idx()], &key_items[is_s.idx()], @@ -462,7 +467,7 @@ impl AccountLeafConfig { // Update key and parent state KeyData::witness_store( - region, + &mut region, offset, &mut pv.memory[key_memory(is_s)], F::zero(), @@ -473,7 +478,7 @@ impl AccountLeafConfig { 0, )?; ParentData::witness_store( - region, + &mut region, offset, &mut pv.memory[parent_memory(is_s)], storage_rlc[is_s.idx()], @@ -485,7 +490,7 @@ impl AccountLeafConfig { // Anything following this node is below the account MainData::witness_store( - region, + &mut region, offset, &mut pv.memory[main_memory()], main_data.proof_type, @@ -497,37 +502,37 @@ impl AccountLeafConfig { // Proof types let is_non_existing_proof = self.is_non_existing_account_proof.assign( - region, + &mut region, offset, main_data.proof_type.scalar(), MPTProofType::AccountDoesNotExist.scalar(), )? == true.scalar(); let is_account_delete_mod = self.is_account_delete_mod.assign( - region, + &mut region, offset, main_data.proof_type.scalar(), MPTProofType::AccountDestructed.scalar(), )? == true.scalar(); let is_nonce_mod = self.is_nonce_mod.assign( - region, + &mut region, offset, main_data.proof_type.scalar(), MPTProofType::NonceChanged.scalar(), )? == true.scalar(); let is_balance_mod = self.is_balance_mod.assign( - region, + &mut region, offset, main_data.proof_type.scalar(), MPTProofType::BalanceChanged.scalar(), )? == true.scalar(); let is_storage_mod = self.is_storage_mod.assign( - region, + &mut region, offset, main_data.proof_type.scalar(), MPTProofType::StorageChanged.scalar(), )? == true.scalar(); let is_codehash_mod = self.is_codehash_mod.assign( - region, + &mut region, offset, main_data.proof_type.scalar(), MPTProofType::CodeHashExists.scalar(), @@ -535,7 +540,7 @@ impl AccountLeafConfig { // Drifted leaf handling self.drifted.assign( - region, + &mut region, offset, &parent_data, &account.drifted_rlp_bytes, @@ -545,7 +550,7 @@ impl AccountLeafConfig { // Wrong leaf handling self.wrong.assign( - region, + &mut region, offset, is_non_existing_proof, &key_rlc, @@ -572,8 +577,8 @@ impl AccountLeafConfig { } else { (MPTProofType::Disabled, vec![0.scalar(); 2]) }; - ctx.mpt_table.assign_cached( - region, + mpt_config.mpt_table.assign_cached( + &mut region, offset, &MptUpdateRow { address_rlc: Value::known(account.address.rlc_value(pv.r)), diff --git a/zkevm-circuits/src/mpt_circuit/extension_branch.rs b/zkevm-circuits/src/mpt_circuit/extension_branch.rs index e0fa51d945..6d9309fd78 100644 --- a/zkevm-circuits/src/mpt_circuit/extension_branch.rs +++ b/zkevm-circuits/src/mpt_circuit/extension_branch.rs @@ -1,7 +1,7 @@ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - plonk::{Error, VirtualCells}, + plonk::{Error, VirtualCells}, circuit::Region, }; use super::{ @@ -183,31 +183,36 @@ impl ExtensionBranchConfig { pub(crate) fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, S>, + region: &mut Region, + challenges: &S, mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, node: &Node, rlp_values: &[RLPItemWitness], ) -> Result<(), Error> { + let mut region = CachedRegion::new( + region, + challenges + ); let extension_branch = &node.extension_branch.clone().unwrap(); self.is_extension - .assign(region, offset, extension_branch.is_extension.scalar())?; + .assign(&mut region, offset, extension_branch.is_extension.scalar())?; let key_data = self.key_data - .witness_load(region, offset, &pv.memory[key_memory(true)], 0)?; + .witness_load(&mut region, offset, &pv.memory[key_memory(true)], 0)?; let mut parent_data = vec![ParentDataWitness::default(); 2]; for is_s in [true, false] { parent_data[is_s.idx()] = self.parent_data[is_s.idx()].witness_load( - region, + &mut region, offset, &mut pv.memory[parent_memory(is_s)], 0, )?; self.is_placeholder[is_s.idx()].assign( - region, + &mut region, offset, extension_branch.is_placeholder[is_s.idx()].scalar(), )?; @@ -221,7 +226,7 @@ impl ExtensionBranchConfig { // Extension if extension_branch.is_extension { self.extension.assign( - region, + &mut region, mpt_config, pv, offset, @@ -238,7 +243,7 @@ impl ExtensionBranchConfig { // Branch let (key_rlc_post_branch, key_rlc_post_drifted, key_mult_post_branch, mod_node_hash_rlc) = self.branch.assign( - region, + &mut region, mpt_config, pv, offset, @@ -255,7 +260,7 @@ impl ExtensionBranchConfig { for is_s in [true, false] { if !extension_branch.is_placeholder[is_s.idx()] { KeyData::witness_store( - region, + &mut region, offset, &mut pv.memory[key_memory(is_s)], key_rlc_post_branch, @@ -266,7 +271,7 @@ impl ExtensionBranchConfig { 0, )?; ParentData::witness_store( - region, + &mut region, offset, &mut pv.memory[parent_memory(is_s)], mod_node_hash_rlc[is_s.idx()], @@ -276,7 +281,7 @@ impl ExtensionBranchConfig { )?; } else { KeyData::witness_store( - region, + &mut region, offset, &mut pv.memory[key_memory(is_s)], key_data.rlc, @@ -287,7 +292,7 @@ impl ExtensionBranchConfig { num_nibbles, )?; ParentData::witness_store( - region, + &mut region, offset, &mut pv.memory[parent_memory(is_s)], parent_data[is_s.idx()].rlc, diff --git a/zkevm-circuits/src/mpt_circuit/start.rs b/zkevm-circuits/src/mpt_circuit/start.rs index 863a582dd2..d827094251 100644 --- a/zkevm-circuits/src/mpt_circuit/start.rs +++ b/zkevm-circuits/src/mpt_circuit/start.rs @@ -19,7 +19,7 @@ use crate::{ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - plonk::{Error, VirtualCells}, + plonk::{Error, VirtualCells}, circuit::Region, }; #[derive(Clone, Debug, Default)] @@ -83,13 +83,19 @@ impl StartConfig { pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, S>, - _ctx: &MPTConfig, + region: &mut Region, + challenges: &S, + mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, node: &Node, rlp_values: &[RLPItemWitness], ) -> Result<(), Error> { + + let mut region = CachedRegion::new( + region, + challenges + ); let start = &node.start.clone().unwrap(); let _root_items = [ @@ -98,7 +104,7 @@ impl StartConfig { ]; self.proof_type - .assign(region, offset, start.proof_type.scalar())?; + .assign(&mut region, offset, start.proof_type.scalar())?; let mut root = vec![0.scalar(); 2]; for is_s in [true, false] { @@ -107,7 +113,7 @@ impl StartConfig { } MainData::witness_store( - region, + &mut region, offset, &mut pv.memory[main_memory()], start.proof_type as usize, @@ -119,7 +125,7 @@ impl StartConfig { for is_s in [true, false] { ParentData::witness_store( - region, + &mut region, offset, &mut pv.memory[parent_memory(is_s)], root[is_s.idx()], @@ -128,7 +134,7 @@ impl StartConfig { root[is_s.idx()], )?; KeyData::witness_store( - region, + &mut region, offset, &mut pv.memory[key_memory(is_s)], F::zero(), diff --git a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs index b9b407d7f2..f54c400ae0 100644 --- a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs @@ -1,7 +1,7 @@ use eth_types::Field; use gadgets::util::Scalar; use halo2_proofs::{ - circuit::{Value}, + circuit::{Value, Region}, plonk::{Error, VirtualCells}, poly::Rotation, }; @@ -259,13 +259,18 @@ impl StorageLeafConfig { pub fn assign>( &self, - region: &mut CachedRegion<'_, '_, F, S>, - ctx: &MPTConfig, + region: &mut Region, + challenges: &S, + mpt_config: &MPTConfig, pv: &mut MPTState, offset: usize, node: &Node, rlp_values: &[RLPItemWitness], ) -> Result<(), Error> { + let mut region = CachedRegion::new( + region, + challenges + ); let storage = &node.storage.clone().unwrap(); let key_items = [ @@ -281,7 +286,7 @@ impl StorageLeafConfig { let main_data = self.main_data - .witness_load(region, offset, &pv.memory[main_memory()], 0)?; + .witness_load(&mut region, offset, &pv.memory[main_memory()], 0)?; let mut key_data = vec![KeyDataWitness::default(); 2]; let mut parent_data = vec![ParentDataWitness::default(); 2]; @@ -289,34 +294,34 @@ impl StorageLeafConfig { let mut value_rlc = vec![0.scalar(); 2]; for is_s in [true, false] { parent_data[is_s.idx()] = self.parent_data[is_s.idx()].witness_load( - region, + &mut region, offset, &mut pv.memory[parent_memory(is_s)], 0, )?; let rlp_key_witness = self.rlp_key[is_s.idx()].assign( - region, + &mut region, offset, &storage.list_rlp_bytes[is_s.idx()], &key_items[is_s.idx()], )?; self.is_not_hashed[is_s.idx()].assign( - region, + &mut region, offset, rlp_key_witness.rlp_list.num_bytes().scalar(), 32.scalar(), )?; key_data[is_s.idx()] = self.key_data[is_s.idx()].witness_load( - region, + &mut region, offset, &mut pv.memory[key_memory(is_s)], 0, )?; KeyData::witness_store( - region, + &mut region, offset, &mut pv.memory[key_memory(is_s)], F::zero(), @@ -340,10 +345,10 @@ impl StorageLeafConfig { .iter() .zip(storage.value_rlp_bytes[is_s.idx()].iter()) { - cell.assign(region, offset, byte.scalar())?; + cell.assign(&mut region, offset, byte.scalar())?; } let value_witness = self.rlp_value[is_s.idx()].assign( - region, + &mut region, offset, &storage.value_rlp_bytes[is_s.idx()], )?; @@ -354,7 +359,7 @@ impl StorageLeafConfig { }; ParentData::witness_store( - region, + &mut region, offset, &mut pv.memory[parent_memory(is_s)], F::zero(), @@ -364,7 +369,7 @@ impl StorageLeafConfig { )?; self.is_in_empty_trie[is_s.idx()].assign( - region, + &mut region, offset, parent_data[is_s.idx()].rlc, pv.r, @@ -372,13 +377,13 @@ impl StorageLeafConfig { } let is_storage_mod_proof = self.is_storage_mod_proof.assign( - region, + &mut region, offset, main_data.proof_type.scalar(), MPTProofType::StorageChanged.scalar(), )? == true.scalar(); let is_non_existing_proof = self.is_non_existing_storage_proof.assign( - region, + &mut region, offset, main_data.proof_type.scalar(), MPTProofType::StorageDoesNotExist.scalar(), @@ -386,7 +391,7 @@ impl StorageLeafConfig { // Drifted leaf handling self.drifted.assign( - region, + &mut region, offset, &parent_data, &storage.drifted_rlp_bytes, @@ -396,7 +401,7 @@ impl StorageLeafConfig { // Wrong leaf handling let key_rlc = self.wrong.assign( - region, + &mut region, offset, is_non_existing_proof, &key_rlc, @@ -415,8 +420,8 @@ impl StorageLeafConfig { } else { MPTProofType::Disabled }; - ctx.mpt_table.assign_cached( - region, + mpt_config.mpt_table.assign_cached( + &mut region, offset, &MptUpdateRow { address_rlc: Value::known(main_data.address_rlc), From 9488dddd8a3e6a1de4e471d7440b412fe3ec8f76 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Wed, 31 May 2023 19:14:23 +0800 Subject: [PATCH 061/102] seperate dynamic lookup from static lookup --- .../src/circuit_tools/constraint_builder.rs | 254 ++++++++++-------- zkevm-circuits/src/circuit_tools/memory.rs | 12 +- .../src/circuit_tools/tests/util.rs | 2 +- zkevm-circuits/src/mpt_circuit.rs | 14 +- zkevm-circuits/src/mpt_circuit/helpers.rs | 8 +- 5 files changed, 166 insertions(+), 124 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools/constraint_builder.rs b/zkevm-circuits/src/circuit_tools/constraint_builder.rs index 24ea3868ec..1531477ce1 100644 --- a/zkevm-circuits/src/circuit_tools/constraint_builder.rs +++ b/zkevm-circuits/src/circuit_tools/constraint_builder.rs @@ -1,5 +1,5 @@ //! Circuit utilities -use std::ops::{Add, Mul}; +use std::{ops::{Add, Mul}, collections::HashMap}; use crate::{evm_circuit::util::rlc, util::Expr}; use eth_types::Field; @@ -9,13 +9,11 @@ use itertools::Itertools; use super::{cell_manager::{Cell, CellManager_, CellTypeTrait, EvmCellType}, cached_region::StoredExpression}; -/// Lookup data +/// Data for dynamic lookup #[derive(Clone)] -pub struct LookupData { +pub struct DynamicData { /// Desciption pub description: &'static str, - /// Lookup tag - pub tag: String, /// Condition under which the lookup needs to be done pub condition: Expression, /// The values to lookup @@ -29,17 +27,21 @@ pub struct ConstraintBuilder { constraints: Vec<(&'static str, Expression)>, /// Max degree of constraints max_degree: usize, + /// conditions for constraints conditions: Vec>, - /// The lookups - pub lookups: Vec>, - /// The lookup tables - pub lookup_tables: Vec>, + /// The lookups generated during synthesis + /// assembles runtime access to RAM + pub dynamic_lookups: HashMap>>, + /// The tables written during synthesis + /// write to RAM + pub dynamic_tables: HashMap>>, + /// Lookups to the preloaded tables with rlc (e.g. kecceck) + /// StoredExpression splits high-degree constraints + pub static_lookups: Vec>, /// CellManager pub cell_manager: Option>, /// Disable macro-generated description for constraints & lookups pub disable_description: bool, - /// Intermediate expression to split high-degree constraints - pub stored_expressions: Vec>, } impl ConstraintBuilder { @@ -48,11 +50,11 @@ impl ConstraintBuilder { constraints: Vec::new(), max_degree, conditions: Vec::new(), - lookups: Vec::new(), - lookup_tables: Vec::new(), + dynamic_lookups: HashMap::new(), + dynamic_tables: HashMap::new(), cell_manager, disable_description: false, - stored_expressions: Vec::new(), + static_lookups: Vec::new(), } } @@ -180,40 +182,36 @@ impl ConstraintBuilder { } } - pub(crate) fn generate_constraints(&self) -> Vec<(&'static str, Expression)> { + pub(crate) fn build_constraints(&self) -> Vec<(&'static str, Expression)> { self.constraints.clone() } - pub(crate) fn generate_lookups>( + pub(crate) fn build_dynamic_lookups>( &self, meta: &mut ConstraintSystem, lookup_names: &[S], ) { for lookup_name in lookup_names.iter() { - let lookups = self - .lookups - .iter() - .cloned() - .filter(|lookup| lookup.tag == lookup_name.as_ref()) - .collect::>(); - for lookup in lookups.iter() { - meta.lookup_any(lookup.description, |_meta| { - let table = self.get_lookup_table_values(lookup_name); - let mut values: Vec<_> = lookup - .values - .iter() - .map(|value| lookup.condition.expr() * value.expr()) - .collect(); - assert!(table.len() >= values.len()); - while values.len() < table.len() { - values.push(0.expr()); - } - table - .iter() - .zip(values.iter()) - .map(|(table, value)| (value.expr(), table.expr())) - .collect() - }); + if let Some(lookups) = self.dynamic_lookups.get(lookup_name.as_ref()){ + for lookup in lookups.iter() { + meta.lookup_any(lookup.description, |_meta| { + let table = self.get_dynamic_table_values(lookup_name); + let mut values: Vec<_> = lookup + .values + .iter() + .map(|value| lookup.condition.expr() * value.expr()) + .collect(); + assert!(table.len() >= values.len()); + while values.len() < table.len() { + values.push(0.expr()); + } + table + .iter() + .zip(values.iter()) + .map(|(table, value)| (value.expr(), table.expr())) + .collect() + }); + } } } } @@ -230,95 +228,139 @@ impl ConstraintBuilder { self.get_condition().unwrap_or_else(|| 1.expr()) } - pub(crate) fn lookup_table>( + pub(crate) fn store_dynamic_table>( &mut self, description: &'static str, tag: S, values: Vec>, ) { let condition = self.get_condition_expr(); - self.lookup_tables.push(LookupData { - description, - tag: tag.as_ref().to_owned(), - condition, - values, - }); + let key = tag.as_ref().to_owned(); + if let Some(table_data) = self.dynamic_tables.get_mut(&key) { + table_data.push( + DynamicData { + description, + condition, + values, + }); + } else { + self.dynamic_tables.insert( + key, + vec![ + DynamicData { + description, + condition, + values, + } + ]); + } } - pub(crate) fn lookup>( + pub(crate) fn add_dynamic_lookup>( &mut self, description: &'static str, tag: S, values: Vec>, ) { let condition = self.get_condition_expr(); - self.lookups.push(LookupData { - description, - tag: tag.as_ref().to_owned(), - condition, - values, - }); - } - - pub(crate) fn get_lookups>(&self, tags: &[S]) -> Vec> { - self.lookups - .iter() - .cloned() - .filter(|lookup| tags.iter().any(|tag| lookup.tag == tag.as_ref())) - .collect::>() + let key = tag.as_ref().to_owned(); + if let Some(lookup_data) = self.dynamic_lookups.get_mut(&key) { + lookup_data.push( + DynamicData { + description, + condition, + values, + }); + } else { + self.dynamic_lookups.insert( + key, + vec![ + DynamicData { + description, + condition, + values, + } + ]); + } } - pub(crate) fn consume_lookups>(&mut self, tags: &[S]) -> Vec> { - let lookups = self.get_lookups(tags); - self.lookups - .retain(|lookup| tags.iter().any(|tag| lookup.tag != tag.as_ref())); - lookups + pub(crate) fn add_static_lookup( + &mut self, + description: &str, + values: Vec>, + ) { + // let lookup = match self.condition_expr_opt() { + // Some(condition) => lookup.conditional(condition), + // None => lookup, + // }; + // let compressed_expr = self.split_expression( + // "Lookup compression", + // rlc::expr(&lookup.input_exprs(), self.challenges.lookup_input()), + // MAX_DEGREE - IMPLICIT_DEGREE, + // ); + // self.static_lookups.push(StaticData { + // description, + // tag: tag.as_ref().to_owned(), + // values, + // }); } - pub(crate) fn get_lookup_table>( + // pub(crate) fn get_dynamic_lookups>(&self, tags: &[S]) -> Vec> { + // self.dynamic_lookups + // .iter() + // .cloned() + // .filter(|lookup| tags.iter().any(|tag| lookup.tag == tag.as_ref())) + // .collect::>() + // } + + // pub(crate) fn consume_dynamic_lookups>(&mut self, tags: &[S]) -> Vec> { + // let lookups = self.get_dynamic_lookups(tags); + // self.dynamic_lookups + // .retain(|lookup| tags.iter().any(|tag| lookup.tag != tag.as_ref())); + // lookups + // } + + pub(crate) fn get_dynamic_table>( &self, tag: S, ) -> (Expression, Vec>) { - let lookups = self - .lookup_tables - .iter() - .filter(|lookup| lookup.tag == tag.as_ref()) - .collect::>(); - + let table_values = self.dynamic_tables + .get(tag.as_ref()) + .expect(&format!("Dynamic table {:?} unfound", tag.as_ref())); merge_values_unsafe( - lookups - .iter() - .map(|lookup| (lookup.condition.clone(), lookup.values.clone())) + table_values.iter() + .map(|table| (table.condition.clone(), table.values.clone())) .collect::>(), ) } - pub(crate) fn get_lookup_table_values>(&self, tag: S) -> Vec> { - let lookup_table = self.get_lookup_table(tag); - // Combine with the merged selector as well - lookup_table - .1 + pub(crate) fn get_dynamic_table_values>( + &self, + tag: S + ) -> Vec> { + let condition_and_values = self.get_dynamic_table(tag); + condition_and_values.1 .iter() - .map(|v| v.expr() * lookup_table.0.expr()) + .map(|value| value.expr() * condition_and_values.0.expr()) .collect::>() } pub(crate) fn generate_lookup_table_checks>(&mut self, tag: S) { - let lookups = self - .lookup_tables - .iter() - .filter(|lookup| lookup.tag == tag.as_ref()) - .collect::>(); - let selectors = lookups - .iter() - .map(|lookup| lookup.condition.expr()) + let table_values = self.dynamic_tables + .get(tag.as_ref()) + .expect(&format!("Dynamic table {:?} unfound", tag.as_ref())) + .clone(); + let selectors = table_values + .into_iter() + .map(|value| { + let sel = value.condition.expr(); + self.require_boolean( + "lookup table condition needs to be boolean", + sel.clone(), + ); + sel + }) .collect::>(); - for selector in selectors.iter() { - self.require_boolean( - "lookup table condition needs to be boolean", - selector.expr(), - ); - } let selector = sum::expr(&selectors); self.require_boolean( "lookup table conditions sum needs to be boolean", @@ -348,7 +390,7 @@ impl ConstraintBuilder { cell.expr() - expr.clone(), ); - self.stored_expressions.push(StoredExpression { + self.static_lookups.push(StoredExpression { name, cell: cell.clone(), cell_type, @@ -366,7 +408,7 @@ impl ConstraintBuilder { cell_type: C, ) -> Option<&StoredExpression> { let expr_id = expr.identifier(); - self.stored_expressions + self.static_lookups .iter() .find(|&e| e.cell_type == cell_type && e.expr_id == expr_id) } @@ -428,7 +470,7 @@ impl ConstraintBuilder { pub(crate) fn merge_lookups( cb: &mut ConstraintBuilder, - lookups: Vec>, + lookups: Vec>, ) -> (Expression, Vec>) { merge_values( cb, @@ -888,14 +930,14 @@ macro_rules! _require { ), false => "" }; - $cb.lookup( + $cb.add_dynamic_lookup( description, $tag.to_string(), vec![$($v.expr(),)*], ); }}; ($cb:expr, $descr:expr, ($($v:expr),+) => @$tag:expr) => {{ - $cb.lookup( + $cb.add_dynamic_lookup( Box::leak($descr.into_boxed_str()), $tag.to_string(), vec![$($v.expr(),)*], @@ -912,14 +954,14 @@ macro_rules! _require { ), false => "" }; - $cb.lookup( + $cb.add_dynamic_lookup( description, $tag.to_string(), $values.clone(), ); }}; ($cb:expr, $descr:expr, $values:expr => @$tag:expr) => {{ - $cb.lookup( + $cb.add_dynamic_lookup( Box::leak($descr.to_string().into_boxed_str()), $tag.to_string(), $values.clone(), @@ -941,7 +983,7 @@ macro_rules! _require { ), false => "", }; - $cb.lookup_table( + $cb.store_dynamic_table( description, $tag.to_string(), vec![$($v.expr(),)*], @@ -959,7 +1001,7 @@ macro_rules! _require { ), false => "", }; - $cb.lookup_table( + $cb.store_dynamic_table( description, $tag.to_string(), $values, diff --git a/zkevm-circuits/src/circuit_tools/memory.rs b/zkevm-circuits/src/circuit_tools/memory.rs index d2d94869c4..7908914d1b 100644 --- a/zkevm-circuits/src/circuit_tools/memory.rs +++ b/zkevm-circuits/src/circuit_tools/memory.rs @@ -59,13 +59,13 @@ impl Memory { self.columns.clone() } - pub(crate) fn generate_constraints( + pub(crate) fn build_constraints( &self, cb: &mut ConstraintBuilder, is_first_row: Expression, ) { for bank in self.banks.iter() { - bank.generate_constraints(cb, is_first_row.expr()); + bank.build_constraints(cb, is_first_row.expr()); cb.generate_lookup_table_checks(bank.tag()); } } @@ -171,7 +171,7 @@ impl MemoryBank { key: Expression, values: &[Expression], ) { - cb.lookup(description, self.tag(), self.insert_key(key, values)); + cb.add_dynamic_lookup(description, self.tag(), self.insert_key(key, values)); } pub(crate) fn store( @@ -190,7 +190,7 @@ impl MemoryBank { key: Expression, values: &[Expression], ) { - cb.lookup_table("memory store", self.tag(), self.insert_key(key, values)); + cb.store_dynamic_table("memory store", self.tag(), self.insert_key(key, values)); } pub(crate) fn witness_store(&mut self, offset: usize, values: &[F]) { @@ -206,12 +206,12 @@ impl MemoryBank { self.store_offsets.clear(); } - pub(crate) fn generate_constraints( + pub(crate) fn build_constraints( &self, cb: &mut ConstraintBuilder, is_first_row: Expression, ) { - let lookup_table = cb.get_lookup_table(self.tag()); + let lookup_table = cb.get_dynamic_table(self.tag()); crate::circuit!([meta, cb], { ifx! {is_first_row => { require!(self.cur.expr() => 0); diff --git a/zkevm-circuits/src/circuit_tools/tests/util.rs b/zkevm-circuits/src/circuit_tools/tests/util.rs index 086d16370d..73ad552627 100644 --- a/zkevm-circuits/src/circuit_tools/tests/util.rs +++ b/zkevm-circuits/src/circuit_tools/tests/util.rs @@ -150,7 +150,7 @@ impl TestConfig { ); }) }); - cb.generate_constraints() + cb.build_constraints() }); Self { diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index e26b43757a..37fb8b13b0 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -285,11 +285,11 @@ impl MPTConfig { }} // Memory banks - ctx.memory.generate_constraints(&mut cb.base, f!(q_first)); + ctx.memory.build_constraints(&mut cb.base, f!(q_first)); }} }); - cb.base.generate_constraints() + cb.base.build_constraints() }); let disable_lookups: usize = var("DISABLE_LOOKUPS") @@ -297,7 +297,7 @@ impl MPTConfig { .parse() .expect("Cannot parse DISABLE_LOOKUPS env var as usize"); if disable_lookups == 0 { - cb.base.generate_lookups( + cb.base.build_dynamic_lookups( meta, &[ vec!["fixed".to_string() /* , "keccak".to_string() */], @@ -306,17 +306,17 @@ impl MPTConfig { .concat(), ); } else if disable_lookups == 1 { - cb.base.generate_lookups( + cb.base.build_dynamic_lookups( meta, &[vec!["keccak".to_string()], ctx.memory.tags()].concat(), ); } else if disable_lookups == 2 { - cb.base.generate_lookups(meta, &ctx.memory.tags()); + cb.base.build_dynamic_lookups(meta, &ctx.memory.tags()); } else if disable_lookups == 3 { cb.base - .generate_lookups(meta, &["fixed".to_string(), "keccak".to_string()]); + .build_dynamic_lookups(meta, &["fixed".to_string(), "keccak".to_string()]); } else if disable_lookups == 4 { - cb.base.generate_lookups(meta, &["keccak".to_string()]); + cb.base.build_dynamic_lookups(meta, &["keccak".to_string()]); } println!("num lookups: {}", meta.lookups().len()); diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index 92ed4ed0f1..6ea807908f 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -867,22 +867,22 @@ impl MPTConstraintBuilder { self.base.require_boolean(name, value) } - pub(crate) fn lookup>( + pub(crate) fn add_dynamic_lookup>( &mut self, description: &'static str, tag: S, values: Vec> ) { - self.base.lookup(description, tag, values) + self.base.add_dynamic_lookup(description, tag, values) } - pub(crate) fn lookup_table>( + pub(crate) fn store_dynamic_table>( &mut self, description: &'static str, tag: S, values: Vec> ) { - self.base.lookup_table(description, tag, values) + self.base.store_dynamic_table(description, tag, values) } pub(crate) fn push_condition(&mut self, condition: Expression) { From 73b2aebca9400ac8b31c9394fb726690dbfe0b74 Mon Sep 17 00:00:00 2001 From: Chih Cheng Liang Date: Wed, 31 May 2023 21:17:13 +0800 Subject: [PATCH 062/102] Remove keccak256 crate and migrate keccak plain to eth-types (#1440) ### Description - We remove the keccak256 crate. - We migrate the keccak256 plain implementation to the eth-types crate. As we migrate keccak circuit to the zkevm-crate, most of the functions left in keccak256 crate are unused except of the plain keccak hash implementation. Most of the crates in the codebase depend on keccak256 crate because they use the plain keccak hash. The plain keccak hash is only 300 lines big. It would be beneficial to keep a plain implementation for people to audit the optimized keccak circuit. ### Type of change Bug fix (non-breaking change which fixes an issue) --- .github/labeler.yml | 2 - Cargo.lock | 693 +----------------- Cargo.toml | 1 - bus-mapping/Cargo.toml | 1 - circuit-benchmarks/Cargo.toml | 1 - eth-types/Cargo.toml | 1 - eth-types/src/geth_types.rs | 8 +- .../src/plain.rs => eth-types/src/keccak.rs | 167 +++-- eth-types/src/lib.rs | 2 + keccak256/Cargo.toml | 23 - keccak256/src/arith_helpers.rs | 228 ------ keccak256/src/common.rs | 49 -- keccak256/src/gate_helpers.rs | 28 - keccak256/src/keccak_arith.rs | 366 --------- keccak256/src/lib.rs | 10 - testool/Cargo.toml | 1 - testool/src/compiler.rs | 7 +- zkevm-circuits/Cargo.toml | 1 - zkevm-circuits/src/pi_circuit.rs | 3 +- zkevm-circuits/src/table.rs | 3 +- zkevm-circuits/src/tx_circuit/sign_verify.rs | 10 +- zkevm-circuits/src/util.rs | 7 +- 22 files changed, 141 insertions(+), 1471 deletions(-) rename keccak256/src/plain.rs => eth-types/src/keccak.rs (59%) delete mode 100644 keccak256/Cargo.toml delete mode 100644 keccak256/src/arith_helpers.rs delete mode 100644 keccak256/src/common.rs delete mode 100644 keccak256/src/gate_helpers.rs delete mode 100644 keccak256/src/keccak_arith.rs delete mode 100644 keccak256/src/lib.rs diff --git a/.github/labeler.yml b/.github/labeler.yml index 55b78caf22..7ab7550300 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -16,8 +16,6 @@ crate-geth-utils: - geth-utils/**/* crate-integration-tests: - integration-tests/**/* -crate-keccak: - - keccak256/**/* crate-mock: - mock/**/* crate-prover: diff --git a/Cargo.lock b/Cargo.lock index e0d8e8fceb..54417fccd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "aes" version = "0.7.5" @@ -51,15 +45,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anyhow" version = "1.0.69" @@ -123,7 +108,7 @@ checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ "futures", "pharos", - "rustc_version 0.4.0", + "rustc_version", ] [[package]] @@ -418,10 +403,9 @@ dependencies = [ "ethers-core", "ethers-providers", "gadgets", - "halo2_proofs 0.2.0", + "halo2_proofs", "hex", "itertools", - "keccak256", "lazy_static", "log", "mock", @@ -475,12 +459,6 @@ dependencies = [ "syn", ] -[[package]] -name = "bytemuck" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393" - [[package]] name = "byteorder" version = "1.4.3" @@ -514,13 +492,8 @@ version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ - "iana-time-zone", - "js-sys", "num-integer", "num-traits", - "time", - "wasm-bindgen", - "winapi", ] [[package]] @@ -541,9 +514,8 @@ dependencies = [ "env_logger", "eth-types", "ethers-signers", - "halo2_proofs 0.2.0", + "halo2_proofs", "itertools", - "keccak256", "mock", "rand", "rand_chacha", @@ -563,7 +535,7 @@ dependencies = [ "clap_lex", "indexmap", "once_cell", - "strsim 0.10.0", + "strsim", "termcolor", "textwrap", ] @@ -613,25 +585,6 @@ dependencies = [ "syn", ] -[[package]] -name = "cmake" -version = "0.1.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c" -dependencies = [ - "cc", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "coins-bip32" version = "0.7.0" @@ -689,12 +642,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "colored" version = "2.0.0" @@ -706,12 +653,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "const-cstr" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" - [[package]] name = "const-oid" version = "0.9.2" @@ -736,59 +677,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "core-graphics" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" -dependencies = [ - "bitflags", - "core-foundation", - "core-graphics-types", - "foreign-types", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" -dependencies = [ - "bitflags", - "core-foundation", - "foreign-types", - "libc", -] - -[[package]] -name = "core-text" -version = "19.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" -dependencies = [ - "core-foundation", - "core-graphics", - "foreign-types", - "libc", -] - [[package]] name = "cpufeatures" version = "0.2.5" @@ -798,15 +686,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - [[package]] name = "crossbeam-channel" version = "0.5.6" @@ -941,82 +820,14 @@ dependencies = [ "cipher", ] -[[package]] -name = "cxx" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "darling" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" -dependencies = [ - "darling_core 0.10.2", - "darling_macro 0.10.2", -] - [[package]] name = "darling" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ - "darling_core 0.13.4", - "darling_macro 0.13.4", -] - -[[package]] -name = "darling_core" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.9.3", - "syn", + "darling_core", + "darling_macro", ] [[package]] @@ -1029,18 +840,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" -dependencies = [ - "darling_core 0.10.2", - "quote", + "strsim", "syn", ] @@ -1050,7 +850,7 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ - "darling_core 0.13.4", + "darling_core", "quote", "syn", ] @@ -1075,31 +875,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "derive_builder" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0" -dependencies = [ - "darling 0.10.2", - "derive_builder_core", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_builder_core" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef" -dependencies = [ - "darling 0.10.2", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "derive_more" version = "0.99.17" @@ -1109,7 +884,7 @@ dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn", ] @@ -1179,33 +954,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "dlib" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" -dependencies = [ - "libloading", -] - [[package]] name = "dunce" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" -[[package]] -name = "dwrote" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" -dependencies = [ - "lazy_static", - "libc", - "winapi", - "wio", -] - [[package]] name = "ecc" version = "0.1.0" @@ -1398,7 +1152,7 @@ version = "0.1.0" dependencies = [ "ethers-core", "ethers-signers", - "halo2_proofs 0.2.0", + "halo2_proofs", "hex", "itertools", "lazy_static", @@ -1409,7 +1163,6 @@ dependencies = [ "serde", "serde_json", "serde_with", - "sha3 0.10.7", "strum", "strum_macros", "subtle", @@ -1544,7 +1297,7 @@ dependencies = [ "ethers-core", "getrandom", "reqwest", - "semver 1.0.16", + "semver", "serde", "serde-aux", "serde_json", @@ -1652,7 +1405,7 @@ dependencies = [ "path-slash", "rayon", "regex", - "semver 1.0.16", + "semver", "serde", "serde_json", "solang-parser", @@ -1710,7 +1463,6 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ - "bitvec 1.0.1", "rand_core", "subtle", ] @@ -1754,68 +1506,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" -[[package]] -name = "flate2" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "float-ord" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" - [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "font-kit" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21fe28504d371085fae9ac7a3450f0b289ab71e07c8e57baa3fb68b9e57d6ce5" -dependencies = [ - "bitflags", - "byteorder", - "core-foundation", - "core-graphics", - "core-text", - "dirs-next", - "dwrote", - "float-ord", - "freetype", - "lazy_static", - "libc", - "log", - "pathfinder_geometry", - "pathfinder_simd", - "walkdir", - "winapi", - "yeslogic-fontconfig-sys", -] - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.1.0" @@ -1825,27 +1521,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "freetype" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee38378a9e3db1cc693b4f88d166ae375338a0ff75cb8263e1c601d51f35dc6" -dependencies = [ - "freetype-sys", - "libc", -] - -[[package]] -name = "freetype-sys" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" -dependencies = [ - "cmake", - "libc", - "pkg-config", -] - [[package]] name = "funty" version = "2.0.0" @@ -1973,7 +1648,7 @@ version = "0.1.0" dependencies = [ "digest 0.7.6", "eth-types", - "halo2_proofs 0.2.0", + "halo2_proofs", "rand", "rand_xorshift", "sha3 0.7.3", @@ -2027,20 +1702,10 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] -[[package]] -name = "gif" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" -dependencies = [ - "color_quant", - "weezl", -] - [[package]] name = "glob" version = "0.3.1" @@ -2097,22 +1762,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "halo2_proofs" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e925780549adee8364c7f2b685c753f6f3df23bde520c67416e93bf615933760" -dependencies = [ - "blake2b_simd", - "ff 0.12.1", - "group 0.12.1", - "pasta_curves 0.4.1", - "plotters", - "rand_core", - "rayon", - "tabbycat", -] - [[package]] name = "halo2_proofs" version = "0.2.0" @@ -2139,7 +1788,7 @@ dependencies = [ "lazy_static", "num-bigint", "num-traits", - "pasta_curves 0.5.1", + "pasta_curves", "paste", "rand", "rand_core", @@ -2152,7 +1801,7 @@ name = "halo2wrong" version = "0.1.0" source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_04_20#f72db265aa3cebe297c9b9816e940d0e1d400886" dependencies = [ - "halo2_proofs 0.2.0", + "halo2_proofs", "num-bigint", "num-integer", "num-traits", @@ -2357,30 +2006,6 @@ dependencies = [ "tokio-rustls", ] -[[package]] -name = "iana-time-zone" -version = "0.1.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -2397,21 +2022,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "image" -version = "0.24.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "jpeg-decoder", - "num-rational", - "num-traits", - "png", -] - [[package]] name = "impl-codec" version = "0.6.0" @@ -2493,7 +2103,7 @@ dependencies = [ "env_logger", "eth-types", "ethers", - "halo2_proofs 0.2.0", + "halo2_proofs", "lazy_static", "log", "mock", @@ -2558,12 +2168,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" -[[package]] -name = "jpeg-decoder" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" - [[package]] name = "js-sys" version = "0.3.61" @@ -2607,23 +2211,6 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "keccak256" -version = "0.1.0" -dependencies = [ - "env_logger", - "eth-types", - "halo2_proofs 0.1.0", - "itertools", - "lazy_static", - "log", - "num-bigint", - "num-traits", - "plotters", - "pretty_assertions", - "rand", -] - [[package]] name = "lalrpop" version = "0.19.9" @@ -2671,16 +2258,6 @@ version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" -[[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 = "libsecp256k1" version = "0.7.1" @@ -2729,15 +2306,6 @@ dependencies = [ "libsecp256k1-core", ] -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "linked-hash-map" version = "0.5.6" @@ -2812,15 +2380,6 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - [[package]] name = "mio" version = "0.8.5" @@ -2829,7 +2388,7 @@ checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.42.0", ] @@ -3078,21 +2637,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "pasta_curves" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc65faf8e7313b4b1fbaa9f7ca917a0eed499a9663be71477f87993604341d8" -dependencies = [ - "blake2b_simd", - "ff 0.12.1", - "group 0.12.1", - "lazy_static", - "rand", - "static_assertions", - "subtle", -] - [[package]] name = "pasta_curves" version = "0.5.1" @@ -3120,25 +2664,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" -[[package]] -name = "pathfinder_geometry" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" -dependencies = [ - "log", - "pathfinder_simd", -] - -[[package]] -name = "pathfinder_simd" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39fe46acc5503595e5949c17b818714d26fdf9b4920eacf3b2947f0199f4a6ff" -dependencies = [ - "rustc_version 0.3.3", -] - [[package]] name = "pbkdf2" version = "0.10.1" @@ -3227,7 +2752,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ "futures", - "rustc_version 0.4.0", + "rustc_version", ] [[package]] @@ -3322,70 +2847,6 @@ dependencies = [ "spki", ] -[[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - -[[package]] -name = "plotters" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" -dependencies = [ - "chrono", - "font-kit", - "image", - "lazy_static", - "num-traits", - "pathfinder_geometry", - "plotters-backend", - "plotters-bitmap", - "plotters-svg", - "ttf-parser", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" - -[[package]] -name = "plotters-bitmap" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4a1f21490a6cf4a84c272ad20bd7844ed99a3178187a4c5ab7f2051295beef" -dependencies = [ - "gif", - "image", - "plotters-backend", -] - -[[package]] -name = "plotters-svg" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "png" -version = "0.17.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" -dependencies = [ - "bitflags", - "crc32fast", - "flate2", - "miniz_oxide", -] - [[package]] name = "poseidon" version = "0.2.0" @@ -3846,7 +3307,7 @@ dependencies = [ "primitive-types 0.11.1", "rlp", "ruint-macro", - "rustc_version 0.4.0", + "rustc_version", "thiserror", ] @@ -3880,22 +3341,13 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.16", + "semver", ] [[package]] @@ -3969,12 +3421,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" - [[package]] name = "scrypt" version = "0.8.1" @@ -4049,15 +3495,6 @@ dependencies = [ "cc", ] -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.16" @@ -4067,15 +3504,6 @@ dependencies = [ "serde", ] -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - [[package]] name = "send_wrapper" version = "0.6.0" @@ -4151,7 +3579,7 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ - "darling 0.13.4", + "darling", "proc-macro2", "quote", "syn", @@ -4285,7 +3713,7 @@ version = "0.1.0" source = "git+https://github.com/privacy-scaling-explorations/snark-verifier?tag=v2023_04_20#e5d5e4a6ccff2bba71baf77ab7a12b124d6364a1" dependencies = [ "ecc", - "halo2_proofs 0.2.0", + "halo2_proofs", "halo2curves", "hex", "itertools", @@ -4355,12 +3783,6 @@ dependencies = [ "precomputed-hash", ] -[[package]] -name = "strsim" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" - [[package]] name = "strsim" version = "0.10.0" @@ -4419,17 +3841,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tabbycat" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c45590f0f859197b4545be1b17b2bc3cc7bb075f7d1cc0ea1dc6521c0bf256a3" -dependencies = [ - "anyhow", - "derive_builder", - "regex", -] - [[package]] name = "tap" version = "1.0.1" @@ -4469,10 +3880,9 @@ dependencies = [ "ethers-signers", "external-tracer", "glob", - "halo2_proofs 0.2.0", + "halo2_proofs", "handlebars", "hex", - "keccak256", "log", "mock", "once_cell", @@ -4518,17 +3928,6 @@ dependencies = [ "syn", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - [[package]] name = "tiny-keccak" version = "2.0.2" @@ -4703,12 +4102,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" -[[package]] -name = "ttf-parser" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" - [[package]] name = "tungstenite" version = "0.17.3" @@ -4853,12 +4246,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -4975,12 +4362,6 @@ dependencies = [ "webpki", ] -[[package]] -name = "weezl" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" - [[package]] name = "winapi" version = "0.3.9" @@ -5102,15 +4483,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "wio" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" -dependencies = [ - "winapi", -] - [[package]] name = "ws_stream_wasm" version = "0.7.4" @@ -5122,7 +4494,7 @@ dependencies = [ "js-sys", "log", "pharos", - "rustc_version 0.4.0", + "rustc_version", "send_wrapper", "thiserror", "wasm-bindgen", @@ -5154,18 +4526,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" -[[package]] -name = "yeslogic-fontconfig-sys" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2bbd69036d397ebbff671b1b8e4d918610c181c5a16073b96f984a38d08c386" -dependencies = [ - "const-cstr", - "dlib", - "once_cell", - "pkg-config", -] - [[package]] name = "zeroize" version = "1.5.7" @@ -5187,11 +4547,10 @@ dependencies = [ "ethers-core", "ethers-signers", "gadgets", - "halo2_proofs 0.2.0", + "halo2_proofs", "hex", "integer", "itertools", - "keccak256", "lazy_static", "libsecp256k1", "log", diff --git a/Cargo.toml b/Cargo.toml index be096fc2fb..c8155a1bfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ members = [ "zkevm-circuits", "bus-mapping", "geth-utils", - "keccak256", "gadgets", "integration-tests", "circuit-benchmarks", diff --git a/bus-mapping/Cargo.toml b/bus-mapping/Cargo.toml index 00204bf9b5..3632275fa6 100644 --- a/bus-mapping/Cargo.toml +++ b/bus-mapping/Cargo.toml @@ -8,7 +8,6 @@ license = "MIT OR Apache-2.0" [dependencies] eth-types = { path = "../eth-types" } gadgets = { path = "../gadgets" } -keccak256 = { path = "../keccak256" } mock = { path = "../mock", optional = true } ethers-core = "0.17.0" diff --git a/circuit-benchmarks/Cargo.toml b/circuit-benchmarks/Cargo.toml index 58ee36a853..8f813e749b 100644 --- a/circuit-benchmarks/Cargo.toml +++ b/circuit-benchmarks/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT OR Apache-2.0" halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } ark-std = { version = "0.3", features = ["print-trace"] } zkevm-circuits = { path = "../zkevm-circuits", features = ["test"]} -keccak256 = { path = "../keccak256" } bus-mapping = { path = "../bus-mapping", features = ["test"] } rand_xorshift = "0.3" rand = "0.8" diff --git a/eth-types/Cargo.toml b/eth-types/Cargo.toml index d0d43f8cfc..1050f3efe8 100644 --- a/eth-types/Cargo.toml +++ b/eth-types/Cargo.toml @@ -19,7 +19,6 @@ uint = "0.9.1" itertools = "0.10" libsecp256k1 = "0.7" subtle = "2.4" -sha3 = "0.10" num = "0.4" num-bigint = { version = "0.4" } strum_macros = "0.24" diff --git a/eth-types/src/geth_types.rs b/eth-types/src/geth_types.rs index 5756d29a8c..0b16ab307d 100644 --- a/eth-types/src/geth_types.rs +++ b/eth-types/src/geth_types.rs @@ -1,6 +1,7 @@ //! Types needed for generating Ethereum traces use crate::{ + keccak256, sign_types::{biguint_to_32bytes_le, ct_option_ok_or, recover_pk, SignData, SECP256K1_Q}, AccessList, Address, Block, Bytes, Error, GethExecTrace, Hash, ToBigEndian, ToLittleEndian, ToWord, Word, U64, @@ -15,7 +16,6 @@ use num::Integer; use num_bigint::BigUint; use serde::{Serialize, Serializer}; use serde_with::serde_as; -use sha3::{Digest, Keccak256}; use std::collections::HashMap; /// Definition of all of the data related to an account. @@ -221,11 +221,7 @@ impl Transaction { // msg = rlp([nonce, gasPrice, gas, to, value, data, sig_v, r, s]) let req: TransactionRequest = self.into(); let msg = req.chain_id(chain_id).rlp(); - let msg_hash: [u8; 32] = Keccak256::digest(&msg) - .as_slice() - .to_vec() - .try_into() - .expect("hash length isn't 32 bytes"); + let msg_hash: [u8; 32] = keccak256(&msg); let v = self .v .checked_sub(35 + chain_id * 2) diff --git a/keccak256/src/plain.rs b/eth-types/src/keccak.rs similarity index 59% rename from keccak256/src/plain.rs rename to eth-types/src/keccak.rs index 8540479505..3bef09e94a 100644 --- a/keccak256/src/plain.rs +++ b/eth-types/src/keccak.rs @@ -1,6 +1,51 @@ -use crate::common::*; +//! Plain keccak256 implementation + use itertools::Itertools; +/// The State is a 5x5 matrix of 64 bit lanes. +type State = [[u64; 5]; 5]; + +/// The number of rounds for the 1600 bits permutation used in Keccak-256. See [here](https://github.com/Legrandin/pycryptodome/blob/016252bde04456614b68d4e4e8798bc124d91e7a/src/keccak.c#L230) +const PERMUTATION: usize = 24; + +/// The Keccak [round constants](https://github.com/Legrandin/pycryptodome/blob/016252bde04456614b68d4e4e8798bc124d91e7a/src/keccak.c#L257-L282) +static ROUND_CONSTANTS: [u64; PERMUTATION] = [ + 0x0000000000000001, + 0x0000000000008082, + 0x800000000000808A, + 0x8000000080008000, + 0x000000000000808B, + 0x0000000080000001, + 0x8000000080008081, + 0x8000000000008009, + 0x000000000000008A, + 0x0000000000000088, + 0x0000000080008009, + 0x000000008000000A, + 0x000000008000808B, + 0x800000000000008B, + 0x8000000000008089, + 0x8000000000008003, + 0x8000000000008002, + 0x8000000000000080, + 0x000000000000800A, + 0x800000008000000A, + 0x8000000080008081, + 0x8000000000008080, + 0x0000000080000001, + 0x8000000080008008, +]; + +/// The Keccak [rotation offsets](https://github.com/Legrandin/pycryptodome/blob/016252bde04456614b68d4e4e8798bc124d91e7a/src/keccak.c#L232-L255) +static ROTATION_CONSTANTS: [[u32; 5]; 5] = [ + [0, 36, 3, 41, 18], + [1, 44, 10, 45, 2], + [62, 6, 43, 15, 61], + [28, 55, 25, 21, 56], + [27, 20, 39, 8, 14], +]; + +/// The main keccak object pub struct Keccak { state: State, sponge: Sponge, @@ -21,6 +66,7 @@ impl Default for Keccak { } impl Keccak { + /// Take more input bytes to the state pub fn update(&mut self, input: &[u8]) { let rate = self.sponge.rate; // offset for `input` @@ -67,10 +113,10 @@ impl Keccak { } #[derive(Default)] -pub struct KeccakF {} +struct KeccakF {} impl KeccakF { - pub fn permutations(&self, a: &mut State) { + fn permutations(&self, a: &mut State) { for rc in ROUND_CONSTANTS.iter().take(PERMUTATION) { *a = KeccakF::round_b(*a, *rc); } @@ -84,7 +130,7 @@ impl KeccakF { KeccakF::iota(s4, rc) } - pub fn theta(a: State) -> State { + fn theta(a: State) -> State { let mut c: [u64; 5] = [0; 5]; let mut out: State = [[0; 5]; 5]; @@ -98,7 +144,7 @@ impl KeccakF { out } - pub fn rho(a: State) -> State { + fn rho(a: State) -> State { let mut out: State = [[0; 5]; 5]; for (x, y) in (0..5).cartesian_product(0..5) { out[x][y] = a[x][y].rotate_left(ROTATION_CONSTANTS[x][y]); @@ -106,7 +152,7 @@ impl KeccakF { out } - pub fn pi(a: State) -> State { + fn pi(a: State) -> State { let mut out: State = [[0; 5]; 5]; for (x, y) in (0..5).cartesian_product(0..5) { @@ -115,7 +161,7 @@ impl KeccakF { out } - pub fn xi(a: State) -> State { + fn xi(a: State) -> State { let mut out: State = [[0; 5]; 5]; for (x, y) in (0..5).cartesian_product(0..5) { out[x][y] = a[x][y] ^ (!a[(x + 1) % 5][y] & a[(x + 2) % 5][y]); @@ -123,21 +169,21 @@ impl KeccakF { out } - pub fn iota(a: State, rc: u64) -> State { + fn iota(a: State, rc: u64) -> State { let mut out = a; out[0][0] ^= rc; out } } -pub struct Sponge { +struct Sponge { rate: usize, capacity: usize, keccak_f: KeccakF, } impl Sponge { - pub fn new(rate: usize, capacity: usize) -> Sponge { + fn new(rate: usize, capacity: usize) -> Sponge { Sponge { rate, capacity, @@ -145,7 +191,7 @@ impl Sponge { } } - pub fn absorb(&self, state: &mut State, message: &[u8]) { + fn absorb(&self, state: &mut State, message: &[u8]) { debug_assert!( message.len() % self.rate == 0, "Message is not divisible entirely by bytes rate" @@ -173,7 +219,7 @@ impl Sponge { } } - pub fn squeeze(&self, state: &mut State) -> Vec { + fn squeeze(&self, state: &mut State) -> Vec { let mut output: Vec = vec![]; let output_len: usize = self.capacity / 2; @@ -206,64 +252,57 @@ impl Sponge { words } } -#[cfg(test)] -fn keccak256(msg: &[u8]) -> Vec { - let mut keccak = Keccak::default(); - keccak.update(msg); - let a = keccak.digest(); +/// Convinient method to get 32 bytes digest +pub fn keccak256(msg: &[u8]) -> [u8; 32] { let mut keccak = Keccak::default(); - for byte in msg { - keccak.update(&[*byte]); - } - let b = keccak.digest(); - - assert_eq!(a, b); - - a + keccak.update(msg); + keccak.digest().try_into().expect("keccak outputs 32 bytes") } #[test] -fn test_empty_input() { - let output = [ - 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, - 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112, - ]; - assert_eq!(keccak256(&[]), output); -} +fn test_keccak256() { + fn keccak256(msg: &[u8]) -> Vec { + let mut keccak = Keccak::default(); + keccak.update(msg); + let a = keccak.digest(); + + let mut keccak = Keccak::default(); + for byte in msg { + keccak.update(&[*byte]); + } + let b = keccak.digest(); -#[test] -fn test_short_input() { - let output = [ - 56, 209, 138, 203, 103, 210, 92, 139, 185, 148, 39, 100, 182, 47, 24, 225, 112, 84, 246, - 106, 129, 123, 212, 41, 84, 35, 173, 249, 237, 152, 135, 62, - ]; - assert_eq!(keccak256(&[102, 111, 111, 98, 97, 114]), output); -} + assert_eq!(a, b); -#[test] -fn test_long_input() { - let input = [ - 65, 108, 105, 99, 101, 32, 119, 97, 115, 32, 98, 101, 103, 105, 110, 110, 105, 110, 103, - 32, 116, 111, 32, 103, 101, 116, 32, 118, 101, 114, 121, 32, 116, 105, 114, 101, 100, 32, - 111, 102, 32, 115, 105, 116, 116, 105, 110, 103, 32, 98, 121, 32, 104, 101, 114, 32, 115, - 105, 115, 116, 101, 114, 32, 111, 110, 32, 116, 104, 101, 32, 98, 97, 110, 107, 44, 32, 97, - 110, 100, 32, 111, 102, 32, 104, 97, 118, 105, 110, 103, 32, 110, 111, 116, 104, 105, 110, - 103, 32, 116, 111, 32, 100, 111, 58, 32, 111, 110, 99, 101, 32, 111, 114, 32, 116, 119, - 105, 99, 101, 32, 115, 104, 101, 32, 104, 97, 100, 32, 112, 101, 101, 112, 101, 100, 32, - 105, 110, 116, 111, 32, 116, 104, 101, 32, 98, 111, 111, 107, 32, 104, 101, 114, 32, 115, - 105, 115, 116, 101, 114, 32, 119, 97, 115, 32, 114, 101, 97, 100, 105, 110, 103, 44, 32, - 98, 117, 116, 32, 105, 116, 32, 104, 97, 100, 32, 110, 111, 32, 112, 105, 99, 116, 117, - 114, 101, 115, 32, 111, 114, 32, 99, 111, 110, 118, 101, 114, 115, 97, 116, 105, 111, 110, - 115, 32, 105, 110, 32, 105, 116, 44, 32, 97, 110, 100, 32, 119, 104, 97, 116, 32, 105, 115, - 32, 116, 104, 101, 32, 117, 115, 101, 32, 111, 102, 32, 97, 32, 98, 111, 111, 107, 44, 32, - 116, 104, 111, 117, 103, 104, 116, 32, 65, 108, 105, 99, 101, 32, 119, 105, 116, 104, 111, - 117, 116, 32, 112, 105, 99, 116, 117, 114, 101, 115, 32, 111, 114, 32, 99, 111, 110, 118, - 101, 114, 115, 97, 116, 105, 111, 110, 115, 63, - ]; - let output = [ - 60, 227, 142, 8, 143, 135, 108, 85, 13, 254, 190, 58, 30, 106, 153, 194, 188, 6, 208, 49, - 16, 102, 150, 120, 100, 130, 224, 177, 64, 98, 53, 252, + a + } + let pairs = [ + ( + "", + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + ), + ( + "666f6f626172", + "38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e", + ), + ( + "416c6963652077617320626567696e6e696e6720746f20676574207665727920\ + 7469726564206f662073697474696e672062792068657220736973746572206f\ + 6e207468652062616e6b2c20616e64206f6620686176696e67206e6f7468696e\ + 6720746f20646f3a206f6e6365206f7220747769636520736865206861642070\ + 656570656420696e746f2074686520626f6f6b20686572207369737465722077\ + 61732072656164696e672c2062757420697420686164206e6f20706963747572\ + 6573206f7220636f6e766572736174696f6e7320696e2069742c20616e642077\ + 6861742069732074686520757365206f66206120626f6f6b2c2074686f756768\ + 7420416c69636520776974686f7574207069637475726573206f7220636f6e76\ + 6572736174696f6e733f", + "3ce38e088f876c550dfebe3a1e6a99c2bc06d031106696786482e0b1406235fc", + ), ]; - assert_eq!(keccak256(&input), output); + for (input, output) in pairs { + let input = hex::decode(input).unwrap(); + let output = hex::decode(output).unwrap(); + assert_eq!(keccak256(&input), output); + } } diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index e3417d6e50..c1f4accd34 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -18,7 +18,9 @@ pub mod error; pub mod bytecode; pub mod evm_types; pub mod geth_types; +pub mod keccak; pub mod sign_types; +pub use keccak::{keccak256, Keccak}; pub use bytecode::Bytecode; pub use error::Error; diff --git a/keccak256/Cargo.toml b/keccak256/Cargo.toml deleted file mode 100644 index 490dc87063..0000000000 --- a/keccak256/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "keccak256" -version = "0.1.0" -edition = "2021" -license = "MIT OR Apache-2.0" - -[features] -dev-graph = ["halo2_proofs/dev-graph", "plotters"] - -[dependencies] -halo2_proofs = { version = "0.1.0-beta.1" } -itertools = "0.10.1" -num-bigint = "0.4.2" -num-traits = "0.2.14" -plotters = { version = "0.3.0", optional = true } -eth-types = { path = "../eth-types" } -lazy_static = "1.4" -log = "0.4.14" -env_logger = "0.9" - -[dev-dependencies] -pretty_assertions = "1.0" -rand = "0.8" diff --git a/keccak256/src/arith_helpers.rs b/keccak256/src/arith_helpers.rs deleted file mode 100644 index 4877486b08..0000000000 --- a/keccak256/src/arith_helpers.rs +++ /dev/null @@ -1,228 +0,0 @@ -use crate::common::State; -use eth_types::Field; -use itertools::Itertools; -use log::debug; -use num_bigint::BigUint; -use num_traits::Zero; -use std::ops::{Index, IndexMut}; - -pub const B2: u8 = 2; -pub const B13: u8 = 13; -pub const B9: u8 = 9; - -/// Base 9 coef mapper scalers -/// f_logic(x1, x2, x3, x4) = x1 ^ (!x2 & x3) ^ x4 -/// f_arith(x1, x2, x3, x4) = 2*x1 + x2 + 3*x3 + 2*x4 -/// where x1, x2, x3, x4 are binary. -/// We have the property that `0 <= f_arith(...) < 9` and -/// the map from `f_arith(...)` to `f_logic(...)` is injective. -pub const A1: u64 = 2; -pub const A2: u64 = 1; -pub const A3: u64 = 3; -pub const A4: u64 = 2; - -pub type Lane13 = BigUint; -pub type Lane9 = BigUint; - -#[derive(Debug)] -pub struct StateBigInt { - pub(crate) xy: Vec, -} -impl Default for StateBigInt { - fn default() -> Self { - let mut xy: Vec = Vec::with_capacity(25); - for _ in 0..25 { - xy.push(Zero::zero()); - } - Self { xy } - } -} - -impl From for StateBigInt { - fn from(state: State) -> Self { - let xy = state - .iter() - .flatten() - .map(|num| BigUint::from(*num)) - .collect(); - Self { xy } - } -} - -impl StateBigInt { - pub fn from_state_big_int(a: &StateBigInt, lane_transform: F) -> Self - where - F: Fn(BigUint) -> BigUint, - { - let mut out = StateBigInt::default(); - for (x, y) in (0..5).cartesian_product(0..5) { - out[(x, y)] = lane_transform(a[(x, y)].clone()); - } - out - } -} - -impl Index<(usize, usize)> for StateBigInt { - type Output = BigUint; - fn index(&self, xy: (usize, usize)) -> &Self::Output { - debug_assert!(xy.0 < 5); - debug_assert!(xy.1 < 5); - - &self.xy[xy.0 * 5 + xy.1] - } -} - -impl IndexMut<(usize, usize)> for StateBigInt { - fn index_mut(&mut self, xy: (usize, usize)) -> &mut Self::Output { - debug_assert!(xy.0 < 5); - debug_assert!(xy.1 < 5); - - &mut self.xy[xy.0 * 5 + xy.1] - } -} - -impl Clone for StateBigInt { - fn clone(&self) -> StateBigInt { - let xy = self.xy.clone(); - StateBigInt { xy } - } -} - -pub fn convert_b2_to_b13(a: u64) -> Lane13 { - let mut lane13: BigUint = Zero::zero(); - for i in 0..64 { - let bit = (a >> i) & 1; - lane13 += bit * BigUint::from(B13).pow(i); - } - lane13 -} - -pub fn convert_b2_to_b9(a: u64) -> Lane9 { - let mut lane9: BigUint = Zero::zero(); - for i in 0..64 { - let bit = (a >> i) & 1; - lane9 += bit * BigUint::from(B9).pow(i); - } - lane9 -} - -/// Maps a sum of 12 bits to the XOR result of 12 bits. -/// -/// The input `x` is a chunk of a base 13 number and it represents the -/// arithmatic sum of 12 bits. Asking the result of the 12 bits XORed together -/// is equivalent of asking if `x` being an odd number. -/// -/// For example, if we have 5 bits set and 7 bits unset, then we have `x` as 5 -/// and the xor result to be 1. -pub fn convert_b13_coef(x: u8) -> u8 { - debug_assert!(x < 13); - x & 1 -} - -/// Maps the arithmatic result `2*a + b + 3*c + 2*d` to the bit operation result -/// `a ^ (~b & c) ^ d` -/// -/// The input `x` is a chunk of a base 9 number and it represents the arithmatic -/// result of `2*a + b + 3*c + 2*d`, where `a`, `b`, `c`, and `d` each is a bit. -pub fn convert_b9_coef(x: u8) -> u8 { - debug_assert!(x < 9); - let bit_table: [u8; 9] = [0, 0, 1, 1, 0, 0, 1, 1, 0]; - bit_table[x as usize] -} - -// We assume the input comes from Theta step and has 65 chunks -// expecting outputs from theta gate -pub fn convert_b13_lane_to_b9(x: Lane13, rot: u32) -> Lane9 { - // 65 chunks - let mut chunks = x.to_radix_le(B13.into()); - chunks.resize(65, 0); - // 0 and 64 was separated in Theta, we now combined them together - let special = chunks.first().unwrap() + chunks.get(64).unwrap(); - // middle 63 chunks - let middle = chunks.get(1..64).unwrap(); - // split at offset - let (left, right) = middle.split_at(63 - rot as usize); - // rotated has 64 chunks - // left is rotated right, and the right is wrapped over to left - // with the special chunk in the middle - let rotated: Vec = right - .iter() - .chain(vec![special].iter()) - .chain(left.iter()) - .map(|&x| convert_b13_coef(x)) - .collect_vec(); - BigUint::from_radix_le(&rotated, B9.into()).unwrap_or_default() -} - -pub fn convert_lane(lane: BigUint, from_base: u8, to_base: u8, coef_transform: F) -> BigUint -where - F: Fn(u8) -> u8, -{ - let chunks = lane.to_radix_be(from_base.into()); - let converted_chunks: Vec = chunks.iter().map(|&x| coef_transform(x)).collect(); - BigUint::from_radix_be(&converted_chunks, to_base.into()).unwrap_or_default() -} - -pub fn convert_b9_lane_to_b13(x: Lane9) -> Lane13 { - convert_lane(x, B9, B13, convert_b9_coef) -} - -pub fn convert_b9_lane_to_b2(x: Lane9) -> u64 { - convert_lane(x, B9, 2, convert_b9_coef) - .iter_u64_digits() - .take(1) - .next() - .unwrap_or(0) -} - -pub fn convert_b9_lane_to_b2_biguint(x: Lane9) -> BigUint { - convert_lane(x, B9, 2, convert_b9_coef) -} - -pub fn convert_b9_lane_to_b2_normal(x: Lane9) -> u64 { - convert_lane(x, B9, 2, |y| y) - .iter_u64_digits() - .take(1) - .next() - .unwrap_or(0) -} - -/// This function allows us to inpect coefficients of big-numbers in different -/// bases. -pub fn inspect(x: BigUint, name: &str, base: u8) { - let mut chunks = x.to_radix_le(base.into()); - chunks.resize(65, 0); - let info: Vec<(usize, u8)> = (0..65).zip(chunks.iter().copied()).collect_vec(); - debug!("inspect {} {} info {:?}", name, x, info); -} - -pub fn f_from_radix_be(buf: &[u8], base: u8) -> F { - let base = F::from(base as u64); - buf.iter() - .fold(F::ZERO, |acc, &x| acc * base + F::from(x as u64)) -} - -#[cfg(test)] -mod tests { - use super::*; - use num_bigint::BigUint; - #[test] - fn test_convert_b13_lane_to_b9() { - // the number 1 is chosen that `convert_b13_coef` has no effect - let mut a = vec![0, 1, 1, 1]; - a.resize(65, 0); - let lane = BigUint::from_radix_le(&a, B13.into()).unwrap_or_default(); - assert_eq!( - convert_b13_lane_to_b9(lane.clone(), 0), - BigUint::from_radix_le(&a, B9.into()).unwrap_or_default() - ); - - // rotate by 4 - let mut b = vec![0, 0, 0, 0, 0, 1, 1, 1]; - b.resize(65, 0); - assert_eq!( - convert_b13_lane_to_b9(lane, 4), - BigUint::from_radix_le(&b, B9.into()).unwrap_or_default() - ); - } -} diff --git a/keccak256/src/common.rs b/keccak256/src/common.rs deleted file mode 100644 index 138e3264d0..0000000000 --- a/keccak256/src/common.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! Types and constants of Keccak hash function. The constants can be found in the appendices of or [pycryptodome](https://github.com/Legrandin/pycryptodome). - -/// The State is a 5x5 matrix of 64 bit lanes. -pub type State = [[u64; 5]; 5]; - -/// The number of next_inputs that are used inside the `absorb` circuit. -pub const NEXT_INPUTS_LANES: usize = 17; - -/// The number of rounds for the 1600 bits permutation used in Keccak-256. See [here](https://github.com/Legrandin/pycryptodome/blob/016252bde04456614b68d4e4e8798bc124d91e7a/src/keccak.c#L230) -pub const PERMUTATION: usize = 24; - -/// The Keccak [round constants](https://github.com/Legrandin/pycryptodome/blob/016252bde04456614b68d4e4e8798bc124d91e7a/src/keccak.c#L257-L282) -pub static ROUND_CONSTANTS: [u64; PERMUTATION] = [ - 0x0000000000000001, - 0x0000000000008082, - 0x800000000000808A, - 0x8000000080008000, - 0x000000000000808B, - 0x0000000080000001, - 0x8000000080008081, - 0x8000000000008009, - 0x000000000000008A, - 0x0000000000000088, - 0x0000000080008009, - 0x000000008000000A, - 0x000000008000808B, - 0x800000000000008B, - 0x8000000000008089, - 0x8000000000008003, - 0x8000000000008002, - 0x8000000000000080, - 0x000000000000800A, - 0x800000008000000A, - 0x8000000080008081, - 0x8000000000008080, - 0x0000000080000001, - 0x8000000080008008, -]; - -/// The Keccak [rotation offsets](https://github.com/Legrandin/pycryptodome/blob/016252bde04456614b68d4e4e8798bc124d91e7a/src/keccak.c#L232-L255) -pub static ROTATION_CONSTANTS: [[u32; 5]; 5] = [ - [0, 36, 3, 41, 18], - [1, 44, 10, 45, 2], - [62, 6, 43, 15, 61], - [28, 55, 25, 21, 56], - [27, 20, 39, 8, 14], -]; - -pub const LANE_SIZE: u32 = 64; diff --git a/keccak256/src/gate_helpers.rs b/keccak256/src/gate_helpers.rs deleted file mode 100644 index 1050f9c3ed..0000000000 --- a/keccak256/src/gate_helpers.rs +++ /dev/null @@ -1,28 +0,0 @@ -use eth_types::Field; -use num_bigint::BigUint; - -/// Convert a bigUint value to FieldExt -/// -/// We assume the input value is smaller than the field size -pub fn biguint_to_f(x: &BigUint) -> F { - let mut x_bytes = x.to_bytes_le(); - debug_assert!( - x_bytes.len() <= 32, - "expect len <=32 but got {}", - x_bytes.len() - ); - x_bytes.resize(32, 0); - let x_bytes: [u8; 32] = x_bytes.try_into().unwrap(); - F::from_repr_vartime(x_bytes).unwrap() -} - -pub fn f_to_biguint(x: F) -> BigUint { - BigUint::from_bytes_le(&x.to_repr()) -} - -pub fn biguint_mod(x: &BigUint, modulus: u8) -> u8 { - x.to_radix_le(modulus.into()) - .first() - .copied() - .unwrap_or_default() -} diff --git a/keccak256/src/keccak_arith.rs b/keccak256/src/keccak_arith.rs deleted file mode 100644 index c59b0964f3..0000000000 --- a/keccak256/src/keccak_arith.rs +++ /dev/null @@ -1,366 +0,0 @@ -use crate::{arith_helpers::*, common::*}; -use itertools::Itertools; - -#[derive(Default)] -pub struct KeccakFArith {} - -impl KeccakFArith { - pub fn permute_and_absorb( - a: &mut StateBigInt, - next_inputs: Option<&State>, - ) -> Option { - for rc in ROUND_CONSTANTS.iter().take(PERMUTATION - 1) { - let s1 = KeccakFArith::theta(a); - let s2 = KeccakFArith::rho(&s1); - let s3 = KeccakFArith::pi(&s2); - let s4 = KeccakFArith::xi(&s3); - let s5 = KeccakFArith::iota_b9(&s4, *rc); - *a = StateBigInt::from_state_big_int(&s5, convert_b9_lane_to_b13); - } - let s1 = KeccakFArith::theta(a); - let s2 = KeccakFArith::rho(&s1); - let s3 = KeccakFArith::pi(&s2); - let s4 = KeccakFArith::xi(&s3); - let res = KeccakFArith::mixing(&s4, next_inputs, *ROUND_CONSTANTS.last().unwrap()); - *a = res.clone(); - if next_inputs.is_some() { - Some(res) - } else { - None - } - } - - pub fn theta(a: &StateBigInt) -> StateBigInt { - let mut c: Vec = Vec::with_capacity(5); - let mut out = StateBigInt::default(); - - for x in 0..5 { - c.push(&a[(x, 0)] + &a[(x, 1)] + &a[(x, 2)] + &a[(x, 3)] + &a[(x, 4)]); - } - - for (x, y) in (0..5).cartesian_product(0..5) { - out[(x, y)] = &a[(x, y)] + &c[(x + 4) % 5] + &c[(x + 1) % 5] * B13; - } - out - } - - pub fn rho(a: &StateBigInt) -> StateBigInt { - let mut out = StateBigInt::default(); - for (x, y) in (0..5).cartesian_product(0..5) { - out[(x, y)] = convert_b13_lane_to_b9(a[(x, y)].clone(), ROTATION_CONSTANTS[x][y]); - } - out - } - - pub fn pi(a: &StateBigInt) -> StateBigInt { - let mut out = StateBigInt::default(); - for (x, y) in (0..5).cartesian_product(0..5) { - out[(y, (2 * x + 3 * y) % 5)] = a[(x, y)].clone(); - } - out - } - - pub fn xi(a: &StateBigInt) -> StateBigInt { - let mut out = StateBigInt::default(); - for (x, y) in (0..5).cartesian_product(0..5) { - out[(x, y)] = a[(x, y)].clone() * A1 - + a[((x + 1) % 5, y)].clone() * A2 - + a[((x + 2) % 5, y)].clone() * A3; - } - out - } - - pub fn absorb(a: &StateBigInt, next_input: &State) -> StateBigInt { - let mut out = StateBigInt::default(); - for (x, y) in (0..5).cartesian_product(0..5) { - out[(x, y)] = a[(x, y)].clone() + convert_b2_to_b9(next_input[x][y]) * A4 - } - out - } - - pub fn iota_b9(a: &StateBigInt, rc: u64) -> StateBigInt { - let mut out = a.clone(); - out[(0, 0)] += convert_b2_to_b9(rc) * A4; - out - } - - pub fn iota_b13(a: &StateBigInt, rc: u64) -> StateBigInt { - let mut out = a.clone(); - out[(0, 0)] += convert_b2_to_b13(rc); - out - } - - pub fn mixing(a: &StateBigInt, next_input: Option<&State>, rc: u64) -> StateBigInt { - if let Some(next_input) = next_input { - let out_1 = KeccakFArith::absorb(a, next_input); - - // Base conversion from 9 to 13 - let mut out_2 = StateBigInt::default(); - for (x, y) in (0..5).cartesian_product(0..5) { - out_2[(x, y)] = convert_b9_lane_to_b13(out_1[(x, y)].clone()) - } - KeccakFArith::iota_b13(&out_2, rc) - } else { - KeccakFArith::iota_b9(a, rc) - } - } -} - -pub struct Keccak { - state: State, - sponge: Sponge, -} - -impl Default for Keccak { - fn default() -> Keccak { - let security_level = (1088, 512); - - Keccak { - state: [[0; 5]; 5], - // rate & capacity in bytes - sponge: Sponge::new(security_level.0 / 8, security_level.1 / 8), - } - } -} - -impl Keccak { - pub fn update(&mut self, input: &[u8]) { - let padding_total = self.sponge.rate - (input.len() % self.sponge.rate); - let mut padding: Vec; - - if padding_total == 1 { - padding = vec![0x81]; - } else { - padding = vec![0x01]; - padding.resize(padding_total - 1, 0x00); - padding.push(0x80); - } - - let padded_input: &[u8] = &[input, &padding].concat(); - self.sponge.absorb(&mut self.state, padded_input); - } - - /// Returns keccak hash based on current state - pub fn digest(&mut self) -> Vec { - self.sponge.squeeze(&mut self.state) - } -} - -struct Sponge { - rate: usize, - capacity: usize, -} - -impl Sponge { - pub fn new(rate: usize, capacity: usize) -> Sponge { - Sponge { rate, capacity } - } - - pub fn absorb(&self, state: &mut State, message: &[u8]) { - debug_assert!( - message.len() % self.rate == 0, - "Message is not divisible entirely by bytes rate" - ); - - let chunks_total = message.len() / self.rate; - - let words: Vec = Sponge::bits_to_u64_words_le(message); - - let mut state_bit_int = StateBigInt::default(); - for chunk_i in 0..chunks_total { - let chunk_offset: usize = chunk_i * (self.rate / 8); - let mut x = 0; - let mut y = 0; - let mut next_inputs = State::default(); - for i in 0..(self.rate / 8) { - next_inputs[x][y] = words[chunk_offset + i]; - if x < 5 - 1 { - x += 1; - } else { - y += 1; - x = 0; - } - } - if chunk_i == 0 { - for (x, y) in (0..5).cartesian_product(0..5) { - state_bit_int[(x, y)] = convert_b2_to_b13(next_inputs[x][y]); - } - continue; - } - KeccakFArith::permute_and_absorb(&mut state_bit_int, Some(&next_inputs)); - } - KeccakFArith::permute_and_absorb(&mut state_bit_int, None); - for (x, y) in (0..5).cartesian_product(0..5) { - state[x][y] = convert_b9_lane_to_b2(state_bit_int[(x, y)].clone()) - } - } - - pub fn squeeze(&self, state: &mut State) -> Vec { - let mut output: Vec = vec![]; - - let output_len: usize = self.capacity / 2; - let elems_total: usize = output_len / 8; - let mut counter: usize = 0; - - 'outer: for y in 0..5 { - for sheet in state.iter().take(5) { - output.append(&mut sheet[y].to_le_bytes().to_vec()); - if counter == elems_total { - break 'outer; - } - counter += 1; - } - } - - output.resize(output_len, 0); - output - } - - fn bits_to_u64_words_le(message: &[u8]) -> Vec { - let words_total = message.len() / 8; - let mut words: Vec = vec![0; words_total]; - - for i in 0..words_total { - let mut word_bits: [u8; 8] = Default::default(); - word_bits.copy_from_slice(&message[i * 8..i * 8 + 8]); - words[i] = u64::from_le_bytes(word_bits); - } - words - } -} -#[cfg(test)] -mod tests { - use crate::{ - arith_helpers::*, - keccak_arith::{Keccak, KeccakFArith, State}, - plain::KeccakF, - }; - use itertools::Itertools; - use num_bigint::BigUint; - use num_traits::Zero; - - fn keccak256(msg: &[u8]) -> Vec { - let mut keccak = Keccak::default(); - keccak.update(msg); - keccak.digest() - } - - #[test] - fn test_helpers() { - assert_eq!(convert_b2_to_b13(0b101u64), BigUint::from(170u64)); - assert_eq!(convert_b2_to_b9(0b10u64), BigUint::from(9u64)); - assert_eq!(convert_b2_to_b9(0b101u64), BigUint::from(82u64)); - assert_eq!( - convert_b13_lane_to_b9(BigUint::from(170u64), 0), - BigUint::from(82u64) - ); - assert_eq!( - convert_b9_lane_to_b13(BigUint::from(82u64)), - BigUint::zero() - ); - assert_eq!(convert_b9_lane_to_b2(BigUint::from(82u64)), 0); - assert_eq!( - convert_b9_lane_to_b2(BigUint::from(9u64).pow(63) * 2u64), - 1u64 << 63 - ); - } - - #[test] - fn test_theta_rho() { - let input1: State = [ - [1, 0, 0, 0, 0], - [0, 0, 0, 9223372036854775808, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - ]; - let input2: State = [ - [4398046511105, 8, 2, 268436480, 2305844108725321728], - [ - 17592186044416, - 52776560230400, - 544, - 68719493120, - 2199023255552, - ], - [ - 4398046543872, - 1152921504606846984, - 262144, - 1024, - 1099511627780, - ], - [0, 52776558133248, 514, 268451840, 2305845208236949504], - [17592186077184, 1152921504608944128, 262176, 68719476736, 4], - ]; - for a in [input1, input2] { - let mut in_b13 = StateBigInt::default(); - for (x, y) in (0..5).cartesian_product(0..5) { - in_b13[(x, y)] = convert_b2_to_b13(a[x][y]); - } - let s1 = KeccakF::theta(a); - let s1_arith = KeccakFArith::theta(&in_b13); - for (x, y) in (0..5).cartesian_product(0..5) { - assert_eq!( - s1[x][y], - convert_b9_lane_to_b2_normal(convert_b13_lane_to_b9( - s1_arith[(x, y)].clone(), - 0 - )) - ); - } - let s2 = KeccakF::rho(s1); - let s2_arith = KeccakFArith::rho(&s1_arith); - for (x, y) in (0..5).cartesian_product(0..5) { - let expected = convert_b9_lane_to_b2_normal(s2_arith[(x, y)].clone()); - assert_eq!(s2[x][y], expected); - } - } - } - - #[test] - fn test_empty_input_arith() { - let output = [ - 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, - 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112, - ]; - assert_eq!(keccak256(&[]), output); - } - - #[test] - fn test_short_input_arith() { - let output = [ - 56, 209, 138, 203, 103, 210, 92, 139, 185, 148, 39, 100, 182, 47, 24, 225, 112, 84, - 246, 106, 129, 123, 212, 41, 84, 35, 173, 249, 237, 152, 135, 62, - ]; - assert_eq!(keccak256(&[102, 111, 111, 98, 97, 114]), output); - } - - #[test] - fn test_long_input_arith() { - let input = [ - 65, 108, 105, 99, 101, 32, 119, 97, 115, 32, 98, 101, 103, 105, 110, 110, 105, 110, - 103, 32, 116, 111, 32, 103, 101, 116, 32, 118, 101, 114, 121, 32, 116, 105, 114, 101, - 100, 32, 111, 102, 32, 115, 105, 116, 116, 105, 110, 103, 32, 98, 121, 32, 104, 101, - 114, 32, 115, 105, 115, 116, 101, 114, 32, 111, 110, 32, 116, 104, 101, 32, 98, 97, - 110, 107, 44, 32, 97, 110, 100, 32, 111, 102, 32, 104, 97, 118, 105, 110, 103, 32, 110, - 111, 116, 104, 105, 110, 103, 32, 116, 111, 32, 100, 111, 58, 32, 111, 110, 99, 101, - 32, 111, 114, 32, 116, 119, 105, 99, 101, 32, 115, 104, 101, 32, 104, 97, 100, 32, 112, - 101, 101, 112, 101, 100, 32, 105, 110, 116, 111, 32, 116, 104, 101, 32, 98, 111, 111, - 107, 32, 104, 101, 114, 32, 115, 105, 115, 116, 101, 114, 32, 119, 97, 115, 32, 114, - 101, 97, 100, 105, 110, 103, 44, 32, 98, 117, 116, 32, 105, 116, 32, 104, 97, 100, 32, - 110, 111, 32, 112, 105, 99, 116, 117, 114, 101, 115, 32, 111, 114, 32, 99, 111, 110, - 118, 101, 114, 115, 97, 116, 105, 111, 110, 115, 32, 105, 110, 32, 105, 116, 44, 32, - 97, 110, 100, 32, 119, 104, 97, 116, 32, 105, 115, 32, 116, 104, 101, 32, 117, 115, - 101, 32, 111, 102, 32, 97, 32, 98, 111, 111, 107, 44, 32, 116, 104, 111, 117, 103, 104, - 116, 32, 65, 108, 105, 99, 101, 32, 119, 105, 116, 104, 111, 117, 116, 32, 112, 105, - 99, 116, 117, 114, 101, 115, 32, 111, 114, 32, 99, 111, 110, 118, 101, 114, 115, 97, - 116, 105, 111, 110, 115, 63, - ]; - let output = [ - 60, 227, 142, 8, 143, 135, 108, 85, 13, 254, 190, 58, 30, 106, 153, 194, 188, 6, 208, - 49, 16, 102, 150, 120, 100, 130, 224, 177, 64, 98, 53, 252, - ]; - assert_eq!(keccak256(&input), output); - } -} diff --git a/keccak256/src/lib.rs b/keccak256/src/lib.rs deleted file mode 100644 index 986db13d17..0000000000 --- a/keccak256/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Leave here until #105 uses all the functions that now are -// just used in tests - -pub mod arith_helpers; -pub mod common; -pub mod gate_helpers; -// We build arith module to get test cases for the circuit -pub mod keccak_arith; -// We build plain module for the purpose of reviewing the circuit -pub mod plain; diff --git a/testool/Cargo.toml b/testool/Cargo.toml index 5b4faed255..8af5e49e12 100644 --- a/testool/Cargo.toml +++ b/testool/Cargo.toml @@ -16,7 +16,6 @@ external-tracer = { path="../external-tracer" } glob = "0.3" handlebars = "4.3" hex = "0.4.3" -keccak256 = { path = "../keccak256" } log = "0.4" mock = { path = "../mock" } once_cell = "1.10" diff --git a/testool/src/compiler.rs b/testool/src/compiler.rs index 1a45162a63..b40f8ecb0d 100644 --- a/testool/src/compiler.rs +++ b/testool/src/compiler.rs @@ -1,8 +1,7 @@ #![allow(clippy::map_entry)] use anyhow::{bail, Context, Result}; -use eth_types::{bytecode, Bytecode, Bytes, H256}; -use keccak256::plain::Keccak; +use eth_types::{bytecode, keccak256, Bytecode, Bytes, H256}; use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, @@ -60,9 +59,7 @@ impl Cache { } fn hash(src: &str) -> H256 { - let mut hash = Keccak::default(); - hash.update(src.as_bytes()); - H256::from_slice(&hash.digest()) + H256::from_slice(&keccak256(src.as_bytes())) } } diff --git a/zkevm-circuits/Cargo.toml b/zkevm-circuits/Cargo.toml index 3f0bd6641f..b20410557a 100644 --- a/zkevm-circuits/Cargo.toml +++ b/zkevm-circuits/Cargo.toml @@ -24,7 +24,6 @@ rand_xorshift = "0.3" rand = "0.8" itertools = "0.10.3" lazy_static = "1.4" -keccak256 = { path = "../keccak256"} log = "0.4" env_logger = "0.9" ecdsa = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_04_20" } diff --git a/zkevm-circuits/src/pi_circuit.rs b/zkevm-circuits/src/pi_circuit.rs index 3e45581d89..ccad100902 100644 --- a/zkevm-circuits/src/pi_circuit.rs +++ b/zkevm-circuits/src/pi_circuit.rs @@ -9,10 +9,9 @@ mod test; use eth_types::{ geth_types::{BlockConstants, Transaction}, sign_types::SignData, - Address, BigEndianHash, Field, ToBigEndian, ToLittleEndian, ToScalar, Word, H256, + Address, BigEndianHash, Field, Keccak, ToBigEndian, ToLittleEndian, ToScalar, Word, H256, }; use halo2_proofs::plonk::{Instance, SecondPhase}; -use keccak256::plain::Keccak; use param::*; use std::marker::PhantomData; diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index c9ba47c01a..8ae4b2d90a 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -11,7 +11,7 @@ use crate::{ }; use bus_mapping::circuit_input_builder::{CopyDataType, CopyEvent, CopyStep}; use core::iter::once; -use eth_types::{Field, ToLittleEndian, ToScalar, Word, U256}; +use eth_types::{Field, Keccak, ToLittleEndian, ToScalar, Word, U256}; use gadgets::{ binary_number::{BinaryNumberChip, BinaryNumberConfig}, util::{split_u256, split_u256_limb64}, @@ -22,7 +22,6 @@ use halo2_proofs::{ poly::Rotation, }; use itertools::Itertools; -use keccak256::plain::Keccak; use std::array; use strum_macros::{EnumCount, EnumIter}; diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs index cb8ef25caa..0683ee998f 100644 --- a/zkevm-circuits/src/tx_circuit/sign_verify.rs +++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs @@ -12,7 +12,7 @@ use crate::{ use ecc::{maingate, EccConfig, GeneralEccChip}; use ecdsa::ecdsa::{AssignedEcdsaSig, AssignedPublicKey, EcdsaChip}; use eth_types::{ - self, + self, keccak256, sign_types::{pk_bytes_le, pk_bytes_swap_endianness, SignData}, Field, }; @@ -33,7 +33,6 @@ use rand::SeedableRng; use rand_chacha::ChaCha20Rng; use itertools::Itertools; -use keccak256::plain::Keccak; use log::error; use maingate::{ AssignedValue, MainGate, MainGateConfig, MainGateInstructions, RangeChip, RangeConfig, @@ -506,12 +505,7 @@ impl SignVerifyChip { let pk_le = pk_bytes_le(&sign_data.pk); let pk_be = pk_bytes_swap_endianness(&pk_le); let pk_hash = (!padding) - .then(|| { - let mut keccak = Keccak::default(); - keccak.update(&pk_be); - let hash: [_; 32] = keccak.digest().try_into().expect("vec to array of size 32"); - hash - }) + .then(|| keccak256(&pk_be)) .unwrap_or_default() .map(|byte| Value::known(F::from(byte as u64))); let pk_hash_hi = pk_hash[..12].to_vec(); diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs index 2a20e42e34..4603df4a21 100644 --- a/zkevm-circuits/src/util.rs +++ b/zkevm-circuits/src/util.rs @@ -7,10 +7,9 @@ use halo2_proofs::{ VirtualCells, }, }; -use keccak256::plain::Keccak; use crate::{evm_circuit::util::rlc, table::TxLogFieldTag, witness}; -use eth_types::{Field, ToAddress, Word}; +use eth_types::{keccak256, Field, ToAddress, Word}; pub use ethers_core::types::{Address, U256}; pub use gadgets::util::Expr; @@ -200,9 +199,7 @@ pub fn log2_ceil(n: usize) -> u32 { } pub(crate) fn keccak(msg: &[u8]) -> Word { - let mut keccak = Keccak::default(); - keccak.update(msg); - Word::from_big_endian(keccak.digest().as_slice()) + Word::from_big_endian(keccak256(msg).as_slice()) } pub(crate) fn is_push(byte: u8) -> bool { From 1ec2fe8212dcb11a3b7fd780eb67db41b34cf44a Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Thu, 1 Jun 2023 20:52:32 +0800 Subject: [PATCH 063/102] StoredExpression equality constraint failed, static lookup failed --- .../src/circuit_tools/cached_region.rs | 183 ++++++++++-------- .../src/circuit_tools/cell_manager.rs | 52 ++--- .../src/circuit_tools/constraint_builder.rs | 103 +++++----- zkevm-circuits/src/mpt_circuit.rs | 99 ++++++---- .../src/mpt_circuit/account_leaf.rs | 47 +++-- .../src/mpt_circuit/extension_branch.rs | 28 ++- zkevm-circuits/src/mpt_circuit/helpers.rs | 61 +++++- zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs | 28 +-- zkevm-circuits/src/mpt_circuit/start.rs | 16 +- .../src/mpt_circuit/storage_leaf.rs | 38 ++-- 10 files changed, 377 insertions(+), 278 deletions(-) diff --git a/zkevm-circuits/src/circuit_tools/cached_region.rs b/zkevm-circuits/src/circuit_tools/cached_region.rs index fc1b0f951b..009fd4403e 100644 --- a/zkevm-circuits/src/circuit_tools/cached_region.rs +++ b/zkevm-circuits/src/circuit_tools/cached_region.rs @@ -4,7 +4,7 @@ use crate::{ use eth_types::{Field}; use halo2_proofs::{ circuit::{AssignedCell, Region, Value}, - plonk::{Advice, Assigned, Column, Error, Expression, Fixed}, + plonk::{Advice, Assigned, Column, Error, Expression, Fixed, Any}, poly::Rotation, }; use itertools::Itertools; @@ -37,7 +37,7 @@ impl<'r, F: Field> MacroDescr for Region<'r, F> { pub struct CachedRegion<'r, 'b, F: Field, S: ChallengeSet> { region: &'r mut Region<'b, F>, - advice: HashMap<(usize, usize), F>, + pub advice: HashMap<(usize, usize), F>, challenges: &'r S, disable_description: bool, } @@ -63,92 +63,103 @@ impl<'r, 'b, F: Field, S: ChallengeSet> CachedRegion<'r, 'b, F, S> { self.disable_description } - /// Assign an advice column value (witness). - pub fn assign_advice<'v, V, VR, A, AR>( - &'v mut self, - annotation: A, - column: Column, - offset: usize, - to: V, - ) -> Result, Error> - where - V: Fn() -> Value + 'v, - for<'vr> Assigned: From<&'vr VR>, - A: Fn() -> AR, - AR: Into, - { - // Actually set the value - let res = self.region.assign_advice(annotation, column, offset, &to); - // Cache the value - // Note that the `value_field` in `AssignedCell` might be `Value::unkonwn` if - // the column has different phase than current one, so we call to `to` - // again here to cache the value. - if res.is_ok() { - to().map(|f: VR| { - self.advice.insert((column.index(), offset), Assigned::from(&f).evaluate()); - }); - } - res + /// Assign an advice column value (witness). + pub fn assign_advice<'v, V, VR, A, AR>( + &'v mut self, + annotation: A, + column: Column, + offset: usize, + to: V, + ) -> Result, Error> + where + V: Fn() -> Value + 'v, + for<'vr> Assigned: From<&'vr VR>, + A: Fn() -> AR, + AR: Into, + { + // Actually set the value + let res = self.region.assign_advice(annotation, column, offset, &to); + // Cache the value + // Note that the `value_field` in `AssignedCell` might be `Value::unkonwn` if + // the column has different phase than current one, so we call to `to` + // again here to cache the value. + if res.is_ok() { + to().map(|f: VR| { + self.advice.insert((column.index(), offset), Assigned::from(&f).evaluate()); + }); } + res + } - pub fn assign_fixed<'v, V, VR, A, AR>( - &'v mut self, - annotation: A, - column: Column, - offset: usize, - to: V, - ) -> Result, Error> - where - V: Fn() -> Value + 'v, - for<'vr> Assigned: From<&'vr VR>, - A: Fn() -> AR, - AR: Into, - { - self.region.assign_fixed(annotation, column, offset, &to) - } - - pub fn get_fixed(&self, _row_index: usize, _column_index: usize, _rotation: Rotation) -> F { - unimplemented!("fixed column"); - } - - // StoreExpression 里面调,拿 F 出去 evaluate - pub fn get_advice(&self, row_index: usize, column_index: usize, rotation: Rotation) -> F { - self.advice.get(&(column_index, row_index + rotation.0 as usize)) - .expect("Advice not found") - .clone() - } - - pub fn challenges(&self) -> &S { - self.challenges - } - - - // pub fn word_rlc(&self, n: U256) -> Value { - // self.challenges - // .evm_word() - // .map(|r| rlc::value(&n.to_le_bytes(), r)) - // } - // pub fn empty_code_hash_rlc(&self) -> Value { - // self.word_rlc(CodeDB::empty_code_hash().to_word()) - // } - - - /// Constrains a cell to have a constant value. - /// - /// Returns an error if the cell is in a column where equality has not been - /// enabled. - pub fn constrain_constant( - &mut self, - cell: AssignedCell, - constant: VR, - ) -> Result<(), Error> - where - VR: Into>, - { - self.region.constrain_constant(cell.cell(), constant.into()) - } + pub fn name_column(&mut self, annotation: A, column: T) + where + A: Fn() -> AR, + AR: Into, + T: Into>, + { + self.region + .name_column(&|| annotation().into(), column.into()); } + pub fn assign_fixed<'v, V, VR, A, AR>( + &'v mut self, + annotation: A, + column: Column, + offset: usize, + to: V, + ) -> Result, Error> + where + V: Fn() -> Value + 'v, + for<'vr> Assigned: From<&'vr VR>, + A: Fn() -> AR, + AR: Into, + { + self.region.assign_fixed(annotation, column, offset, &to) + } + + pub fn get_fixed(&self, _row_index: usize, _column_index: usize, _rotation: Rotation) -> F { + unimplemented!("fixed column"); + } + + // StoreExpression 里面调,拿 F 出去 evaluate + pub fn get_advice(&self, row_index: usize, column_index: usize, rotation: Rotation) -> F { + println!("\t get_advice: [{}][{}]", column_index, rotation.0 as usize + row_index); + self.advice.get(&(column_index, row_index + rotation.0 as usize)) + .expect("Advice not found") + .clone() + } + + pub fn challenges(&self) -> &S { + self.challenges + } + + + // pub fn word_rlc(&self, n: U256) -> Value { + // self.challenges + // .evm_word() + // .map(|r| rlc::value(&n.to_le_bytes(), r)) + // } + // pub fn empty_code_hash_rlc(&self) -> Value { + // self.word_rlc(CodeDB::empty_code_hash().to_word()) + // } + + + /// Constrains a cell to have a constant value. + /// + /// Returns an error if the cell is in a column where equality has not been + /// enabled. + pub fn constrain_constant( + &mut self, + cell: AssignedCell, + constant: VR, + ) -> Result<(), Error> + where + VR: Into>, + { + self.region.constrain_constant(cell.cell(), constant.into()) + } +} + #[derive(Debug, Clone)] pub struct StoredExpression { @@ -172,6 +183,9 @@ impl StoredExpression { region: &mut CachedRegion<'_, '_, F, S>, offset: usize, ) -> Result, Error> { + + //println!("____ StoredExpression::assign ____ \n\t {:?} -> {:?}", self.expr_id, self.cell.identifier()); + let value = self.expr.evaluate( &|scalar| Value::known(scalar), &|_| unimplemented!("selector column"), @@ -197,6 +211,7 @@ impl StoredExpression { &|a, scalar| a * Value::known(scalar), ); self.cell.assign_value(region, offset, value)?; + println!("evaluated value: {:?}", value); Ok(value) } } diff --git a/zkevm-circuits/src/circuit_tools/cell_manager.rs b/zkevm-circuits/src/circuit_tools/cell_manager.rs index bba8f6250a..ecda26cb75 100644 --- a/zkevm-circuits/src/circuit_tools/cell_manager.rs +++ b/zkevm-circuits/src/circuit_tools/cell_manager.rs @@ -21,9 +21,9 @@ use strum_macros::EnumIter; pub(crate) struct Cell { // expression for constraint expression: Option>, - column: Option>, + pub column: Option>, // relative position to selector for synthesis - rotation: usize, + pub rotation: usize, } @@ -90,6 +90,10 @@ impl Cell { pub(crate) fn rot(&self, meta: &mut VirtualCells, rot: usize) -> Expression { meta.query_advice(self.column.unwrap(), Rotation((self.rotation + rot) as i32)) } + + pub(crate) fn identifier(&self) -> String { + self.expr().identifier() + } } impl Expr for Cell { @@ -135,10 +139,10 @@ impl CellTypeTrait for EvmCellType { #[derive(Clone, Debug)] pub struct CellConfig { - cell_type: C, - num_columns: usize, - phase: u8, - is_permute: bool, + pub cell_type: C, + pub num_columns: usize, + pub phase: u8, + pub is_permute: bool, } impl From<(C, usize, u8, bool)> for CellConfig { @@ -207,9 +211,9 @@ pub trait CellTypeTrait: pub(crate) struct CellColumn_ { column: Column, index: usize, - cell_type: C, + pub(crate) cell_type: C, height: usize, - expr: Expression, + pub(crate) expr: Expression, } @@ -251,14 +255,14 @@ impl CellManager_ { }); }; - println!("\nInitiating cm:"); + //println!("\nInitiating cm:"); cell_configs .iter() .for_each(|c| { let cols = c.init_columns(meta); let mut cell_list = Vec::with_capacity(cols.len() * max_height); query_expression(meta, |meta| { - println!("cols.len() init {} * {}", cols.len(), max_height); + //println!("cols.len() init {} * {}", cols.len(), max_height); for w in 0..cols.len() { for h in 0..max_height { let cell: Cell<_> = Cell::new(meta, cols[w], offset + h); @@ -274,7 +278,7 @@ impl CellManager_ { } }); cells.insert(c.cell_type, (total_width, cell_list.clone())); - println!("cell type {:?} start with {} for window {}, cell_list {}", c.cell_type, total_width, c.num_columns, cell_list.len()); + //println!("cell type {:?} start with {} for window {}, cell_list {}", c.cell_type, total_width, c.num_columns, cell_list.len()); total_width += cols.len(); }); @@ -295,6 +299,10 @@ impl CellManager_ { .collect() } + pub(crate) fn cell_columns(&self) -> &Vec> { + &self.columns + } + pub(crate) fn get_width(&self) -> usize { self.total_width } @@ -316,21 +324,21 @@ impl CellManager_ { let mut tmp = Vec::with_capacity(window * max_height); for w in 0..window { if max_height < self.max_height { - println!("\n-- set_max_height: {} -> {}", self.max_height, max_height); + //println!("\n-- set_max_height: {} -> {}", self.max_height, max_height); tmp.extend_from_slice(&cells[w * self.max_height..w * self.max_height + max_height]); } else { - println!("\n++ set_max_height: {} -> {}", self.max_height, max_height); + //println!("\n++ set_max_height: {} -> {}", self.max_height, max_height); tmp.extend_from_slice(&cells[w * self.max_height..w * self.max_height + self.max_height]); - print!(" tmp.len() {} -> ", tmp.len()); + //print!(" tmp.len() {} -> ", tmp.len()); let col = tmp.last().unwrap().column(); tmp.extend( (self.max_height..max_height) .map(|h| Cell::new(meta, col, self.offset + h)) ); - print!("{} ", tmp.len()); + //print!("{} ", tmp.len()); } } - println!("added cells for {:?} to {}", cell_type, tmp.len()); + //println!("added cells for {:?} to {}", cell_type, tmp.len()); new_cells.insert(*cell_type, (*start_width, tmp)); }); self.cells = new_cells; @@ -355,7 +363,7 @@ impl CellManager_ { pub(crate) fn get_typed_columns(&self, cell_type: C) -> Vec> { let (start_width, _) = self.cells.get(&cell_type).expect("Cell type not found"); let window = self.get_config(cell_type).num_columns; - self.columns[*start_width..window].to_owned() + self.columns[*start_width..*start_width + window].to_owned() } /// Clears columns record and set new height in cells array @@ -372,15 +380,15 @@ impl CellManager_ { .expect(&format!("Cell type {:?} not found", cell_type)); let window = self.get_config(cell_type).num_columns; - println!("querying {:?} {} cells", cell_type, count); + //println!("querying {:?} {} cells", cell_type, count); if cell_list.len() == 2 || cell_list.len() == 21 { - println!("\n fucked up place, start_width {} window {}", start_width, window); + //println!("\n fucked up place, start_width {} window {}", start_width, window); self.cells .iter() .for_each(|(c, (start, l))| print!("{:?}: {} |", c, l.len()) ); - // println!( + //// println!( // "columns {:?}", self.columns[*start_width..start_width + window].to_vec() // ) } @@ -391,7 +399,7 @@ impl CellManager_ { // Search best cell in window of columns designated for this CellType let (index, height) = self.next_column(cell_type, &self.columns[*start_width..start_width + window]); targets.push(cell_list[index * self.max_height + height].clone()); - // println!("at ({} * {} + {})", index, self.max_height, height); + //// println!("at ({} * {} + {})", index, self.max_height, height); self.columns[start_width + index].height += 1; } targets @@ -411,7 +419,7 @@ impl CellManager_ { best_height = column.height; } } - println!("best pos: {:?}", best_pos); + //println!("best pos: {:?}", best_pos); match best_pos { Some(pos) => pos, // If we reach this case, it means that all the columns of cell_type have assignments diff --git a/zkevm-circuits/src/circuit_tools/constraint_builder.rs b/zkevm-circuits/src/circuit_tools/constraint_builder.rs index 1531477ce1..24b66b617b 100644 --- a/zkevm-circuits/src/circuit_tools/constraint_builder.rs +++ b/zkevm-circuits/src/circuit_tools/constraint_builder.rs @@ -1,13 +1,13 @@ //! Circuit utilities -use std::{ops::{Add, Mul}, collections::HashMap}; +use std::{ops::{Add, Mul}, collections::HashMap, vec}; -use crate::{evm_circuit::util::rlc, util::Expr}; +use crate::{evm_circuit::util::rlc, util::{Expr, Challenges}}; use eth_types::Field; use gadgets::util::{and, sum, Scalar}; use halo2_proofs::plonk::{ConstraintSystem, Expression}; use itertools::Itertools; -use super::{cell_manager::{Cell, CellManager_, CellTypeTrait, EvmCellType}, cached_region::StoredExpression}; +use super::{cell_manager::{Cell, CellManager_, CellTypeTrait, EvmCellType}, cached_region::StoredExpression, table::LookupTable_}; /// Data for dynamic lookup #[derive(Clone)] @@ -41,6 +41,7 @@ pub struct ConstraintBuilder { /// CellManager pub cell_manager: Option>, /// Disable macro-generated description for constraints & lookups + /// for graph display pub disable_description: bool, } @@ -186,6 +187,27 @@ impl ConstraintBuilder { self.constraints.clone() } + pub(crate) fn build_static_lookups( + &self, + meta: &mut ConstraintSystem, + challenge: Expression, + tables: Vec<&dyn LookupTable_> + ) { + println!("____ build_static_lookups ____ \n challen {:?}", challenge); + let cm = self.cell_manager.as_ref().expect("CellManager unset!"); + for table in tables { + let cell_type = table.get_type_(); + for col in cm.get_typed_columns(cell_type) { + meta.lookup_any( + "static lookup", + |meta| { + vec![(col.expr, rlc::expr(&table.table_exprs(meta), challenge.clone()))] + } + ); + } + } + } + pub(crate) fn build_dynamic_lookups>( &self, meta: &mut ConstraintSystem, @@ -284,41 +306,30 @@ impl ConstraintBuilder { } } + + // Todo(Cecilia): incorperate the challenge into CB + // then remove from MPT ctx pub(crate) fn add_static_lookup( &mut self, description: &str, + challenge: Expression, + cell_type: C, values: Vec>, ) { - // let lookup = match self.condition_expr_opt() { - // Some(condition) => lookup.conditional(condition), - // None => lookup, - // }; - // let compressed_expr = self.split_expression( - // "Lookup compression", - // rlc::expr(&lookup.input_exprs(), self.challenges.lookup_input()), - // MAX_DEGREE - IMPLICIT_DEGREE, - // ); - // self.static_lookups.push(StaticData { - // description, - // tag: tag.as_ref().to_owned(), - // values, - // }); + println!("________ add_static_lookup ________ \nchallenge: {:?}", challenge); + let compressed_expr = self.split_expression( + "Lookup compression", + rlc::expr(&values, challenge), + ); + println!("compressed_expr: {:?}", compressed_expr.identifier()); + self.store_expression(description, compressed_expr, cell_type); + } + + + pub(crate) fn get_static_lookups(&self) -> Vec> { + self.static_lookups.clone() } - // pub(crate) fn get_dynamic_lookups>(&self, tags: &[S]) -> Vec> { - // self.dynamic_lookups - // .iter() - // .cloned() - // .filter(|lookup| tags.iter().any(|tag| lookup.tag == tag.as_ref())) - // .collect::>() - // } - - // pub(crate) fn consume_dynamic_lookups>(&mut self, tags: &[S]) -> Vec> { - // let lookups = self.get_dynamic_lookups(tags); - // self.dynamic_lookups - // .retain(|lookup| tags.iter().any(|tag| lookup.tag != tag.as_ref())); - // lookups - // } pub(crate) fn get_dynamic_table>( &self, @@ -374,6 +385,9 @@ impl ConstraintBuilder { expr: Expression, cell_type: C, ) -> Expression { + + println!("\t ____ store_expression ____"); + // Check if we already stored the expression somewhere let stored_expression = self.find_stored_expression(&expr, cell_type); @@ -385,11 +399,11 @@ impl ConstraintBuilder { // Require the stored value to equal the value of the expression let cell = self.query_one(cell_type); let name = format!("{} (stored expression)", name); - self.add_constraint( - Box::leak(name.clone().into_boxed_str()), - cell.expr() - expr.clone(), - ); - + // self.add_constraint( + // Box::leak(name.clone().into_boxed_str()), + // cell.expr() - expr.clone(), + // ); + println!("\n pushing in cell {:?}: {:?}", cell.identifier(), expr.identifier()); self.static_lookups.push(StoredExpression { name, cell: cell.clone(), @@ -417,27 +431,26 @@ impl ConstraintBuilder { &mut self, name: &'static str, expr: Expression, - max_degree: usize, ) -> Expression { - if expr.degree() > max_degree { + if expr.degree() > self.max_degree { match expr { Expression::Negated(poly) => { - Expression::Negated(Box::new(self.split_expression(name, *poly, max_degree))) + Expression::Negated(Box::new(self.split_expression(name, *poly))) } Expression::Scaled(poly, v) => { - Expression::Scaled(Box::new(self.split_expression(name, *poly, max_degree)), v) + Expression::Scaled(Box::new(self.split_expression(name, *poly)), v) } Expression::Sum(a, b) => { - let a = self.split_expression(name, *a, max_degree); - let b = self.split_expression(name, *b, max_degree); + let a = self.split_expression(name, *a); + let b = self.split_expression(name, *b); a + b } Expression::Product(a, b) => { let (mut a, mut b) = (*a, *b); - while a.degree() + b.degree() > max_degree { + while a.degree() + b.degree() > self.max_degree { let mut split = |expr: Expression| { - if expr.degree() > max_degree { - self.split_expression(name, expr, max_degree) + if expr.degree() > self.max_degree { + self.split_expression(name, expr) } else { let cell_type = C::storage_for_expr(&expr); self.store_expression(name, expr, cell_type) diff --git a/zkevm-circuits/src/mpt_circuit.rs b/zkevm-circuits/src/mpt_circuit.rs index 37fb8b13b0..c007d76198 100644 --- a/zkevm-circuits/src/mpt_circuit.rs +++ b/zkevm-circuits/src/mpt_circuit.rs @@ -21,28 +21,29 @@ mod param; mod rlp_gadgets; mod start; mod storage_leaf; -mod witness_row; mod table; +mod witness_row; use self::{ account_leaf::AccountLeafConfig, helpers::{key_memory, RLPItemView}, - witness_row::{StartRowType,ExtensionBranchRowType, AccountRowType, StorageRowType,Node}, + witness_row::{AccountRowType, ExtensionBranchRowType, Node, StartRowType, StorageRowType}, }; use crate::{ assign, assignf, circuit, circuit_tools::{ + cached_region::{CachedRegion, MacroDescr, ChallengeSet}, + cell_manager::{CellManager_, CellTypeTrait, EvmCellType}, memory::Memory, - cached_region::{CachedRegion, MacroDescr}, + table::LookupTable_, }, mpt_circuit::{ helpers::{main_memory, parent_memory, MPTConstraintBuilder, MainRLPGadget}, start::StartConfig, storage_leaf::StorageLeafConfig, }, - circuit_tools::{table::LookupTable_, cell_manager::{CellManager_, CellTypeTrait, EvmCellType}}, table::{KeccakTable, MPTProofType, MptTable}, - util::Challenges, + util::Challenges, evm_circuit::table::Table, }; use extension_branch::ExtensionBranchConfig; use param::HASH_WIDTH; @@ -134,7 +135,7 @@ pub struct MPTConfig { state_machine: StateMachineConfig, pub(crate) mpt_table: MptTable, cb: MPTConstraintBuilder, -} +} /// Enumerator to determine the type of row in the fixed table. #[derive(Clone, Copy, Debug)] @@ -210,29 +211,33 @@ impl MPTConfig { memory: memory.clone(), }; - let rlp_cm = CellManager_::new( meta, // Type, #cols, phase, permutable - vec![(EvmCellType::StoragePhase1, 50, 0, false)], + vec![ + (EvmCellType::StoragePhase1, 50, 0, false), + (EvmCellType::Lookup(Table::Fixed), 5, 0, false) + ], Vec::new(), 0, - 1 + 1, ); let rlp_columns = rlp_cm.get_columns(); let state_cm = CellManager_::new( meta, // Type, #cols, phase, permutable vec![ - (EvmCellType::StoragePhase1, 15, 0, false), - (EvmCellType::LookupByte, 5, 0, false) + (EvmCellType::StoragePhase1, 15, 0, false), + (EvmCellType::LookupByte, 5, 0, false), + (EvmCellType::Lookup(Table::Keccak), 5, 0, false) ], Vec::new(), 0, - 1 + 1, ); let state_columns = state_cm.get_columns(); - let mut cb = MPTConstraintBuilder::new(33 + 10, None); + let mut cb = MPTConstraintBuilder::new(33 + 10, Some(challenges.clone()), None); + println!("_________ create_gate ________"); meta.create_gate("MPT", |meta| { circuit!([meta, cb], { // Populate lookup tables @@ -297,6 +302,11 @@ impl MPTConfig { .parse() .expect("Cannot parse DISABLE_LOOKUPS env var as usize"); if disable_lookups == 0 { + cb.base.build_static_lookups( + meta, + challenges.lookup_input(), + vec![&keccak_table, &fixed_table] + ); cb.base.build_dynamic_lookups( meta, &[ @@ -352,7 +362,7 @@ impl MPTConfig { let mut r = F::zero(); challenges.keccak_input().map(|v| r = v); - + println!("________ MPT::assign ________"); layouter.assign_region( || "MPT", |mut region| { @@ -362,34 +372,35 @@ impl MPTConfig { let mut offset = 0; for node in nodes.iter() { - // Assign bytes - let mut rlp_values = Vec::new(); - let mut cahced_region = CachedRegion::new( + let mut cached_region = CachedRegion::new( &mut region, challenges ); + // Assign bytes + let mut rlp_values = Vec::new(); // Decompose RLP for (idx, bytes) in node.values.iter().enumerate() { let is_nibbles = node.extension_branch.is_some() && idx == ExtensionBranchRowType::KeyC as usize; let rlp_value = self.rlp_item.assign( - &mut cahced_region, + &mut cached_region, offset + idx, bytes, r, is_nibbles, )?; rlp_values.push(rlp_value); - assignf!(cahced_region, (self.rows_left_in_state, offset + idx) => (node.values.len() - idx).scalar())?; + assignf!(cached_region, (self.rows_left_in_state, offset + idx) => (node.values.len() - idx).scalar())?; } + //println!("{} mainRLP ====> cached_region.advice\n {:?}", offset, cached_region.advice); // Assign nodes if node.start.is_some() { - // println!("{}: start", offset); - assign!(region, (self.state_machine.is_start, offset) => "is_start", true.scalar())?; + println!("{}: start", offset); + assign!(cached_region, (self.state_machine.is_start, offset) => "is_start", true.scalar())?; self.state_machine.start_config.assign( - &mut region, + &mut cached_region, challenges, self, &mut pv, @@ -398,10 +409,10 @@ impl MPTConfig { &rlp_values, )?; } else if node.extension_branch.is_some() { - // println!("{}: branch", offset); - assign!(region, (self.state_machine.is_branch, offset) => "is_branch", true.scalar())?; + println!("{}: branch", offset); + assign!(cached_region, (self.state_machine.is_branch, offset) => "is_branch", true.scalar())?; self.state_machine.branch_config.assign( - &mut region, + &mut cached_region, challenges, self, &mut pv, @@ -410,10 +421,10 @@ impl MPTConfig { &rlp_values, )?; } else if node.storage.is_some() { - // println!("{}: storage", offset); - assign!(region, (self.state_machine.is_storage, offset) => "is_storage", true.scalar())?; + println!("{}: storage", offset); + assign!(cached_region, (self.state_machine.is_storage, offset) => "is_storage", true.scalar())?; self.state_machine.storage_config.assign( - &mut region, + &mut cached_region, challenges, self, &mut pv, @@ -422,10 +433,10 @@ impl MPTConfig { &rlp_values, )?; } else if node.account.is_some() { - // println!("{}: account", offset); - assign!(region, (self.state_machine.is_account, offset) => "is_account", true.scalar())?; + println!("{}: account", offset); + assign!(cached_region, (self.state_machine.is_account, offset) => "is_account", true.scalar())?; self.state_machine.account_config.assign( - &mut region, + &mut cached_region, challenges, self, &mut pv, @@ -434,7 +445,7 @@ impl MPTConfig { &rlp_values, )?; } - + self.assign_static_lookups(&mut cached_region, offset); offset += node.values.len(); } @@ -446,16 +457,32 @@ impl MPTConfig { assignf!(region, (self.q_first, offset) => (offset == 0).scalar())?; assignf!(region, (self.q_last, offset) => (offset == height - 2).scalar())?; } + Ok(()) }, )?; - + memory.assign(layouter, height)?; Ok(()) } + fn assign_static_lookups>( + &self, + region: &mut CachedRegion<'_, '_, F, S>, + offset: usize, + ) { + //println!("_________ assign_static_lookups ________ \nstatic_lookups: {:?}\n", self.cb.base.get_static_lookups()); + + self.cb.base.get_static_lookups() + .iter() + .for_each(|stored_expr| { + stored_expr.assign(region, offset).expect("static lookup assignment failed"); + }); + } + + fn load_fixed_table( &self, layouter: &mut impl Layouter, @@ -680,6 +707,8 @@ mod tests { keccak_data, randomness, }; + let prover = MockProver::run(9 /* 9 */, &circuit, vec![]).unwrap(); + assert_eq!(prover.verify_at_rows(0..num_rows, 0..num_rows,), Ok(())); println!("Start graphing"); @@ -695,9 +724,7 @@ mod tests { // Generate the DOT graph string. let dot_string = halo2_proofs::dev::circuit_dot_graph(&circuit); print!("{}", dot_string); - - } } -const debug_file: &'static str = "[[0,1,0,1,249,2,17,249,2,17,13,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0],[0,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,0,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,0,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,0,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,0,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,0,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,0,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,0,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,0,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,0,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,0,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,0,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,0,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,0,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,198,110,59,110,207,162,15,138,151,80,193,238,182,30,35,42,168,192,180,204,238,61,99,82,32,113,75,76,38,31,245,168,0,160,208,11,7,160,57,118,105,130,12,148,160,224,101,79,108,119,75,73,27,251,23,112,202,194,98,232,67,35,41,20,109,227,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,0,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,0,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,17],[0,1,0,1,249,2,17,249,2,17,14,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,0,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,0,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,0,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,0,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,0,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,0,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,0,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,0,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,0,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,0,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,0,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,0,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,0,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,0,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,66,160,223,51,184,103,51,48,79,182,55,124,160,55,136,72,34,106,234,196,136,142,67,163,253,247,97,56,227,113,81,112,0,160,156,207,34,126,96,200,143,86,98,67,48,239,210,146,94,107,198,11,34,45,151,240,146,143,132,124,18,87,19,78,100,125,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,0,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,7,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,0,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,0,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,0,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,0,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,0,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,0,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,0,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,68,171,218,249,64,4,214,12,108,176,191,110,229,129,30,147,162,111,141,248,90,65,72,139,199,122,223,7,22,19,86,170,0,160,139,236,208,88,153,113,82,137,105,145,232,206,194,251,94,134,60,159,209,170,140,223,189,13,150,246,4,251,15,48,51,104,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,0,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,0,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,0,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,0,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,0,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,0,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,0,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,0,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,8,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,0,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,0,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,0,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,0,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,0,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,0,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,0,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,0,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,154,52,165,162,92,151,34,100,231,147,116,21,226,254,143,170,231,209,154,231,199,183,20,105,49,183,6,201,128,11,16,232,0,160,159,130,229,165,212,147,78,44,146,124,254,74,180,62,107,231,41,115,95,72,27,6,25,183,104,151,116,137,84,204,53,189,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,0,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,0,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,0,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,0,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,0,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,0,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,0,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,15,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,0,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,0,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,0,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,0,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,0,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,0,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,0,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,0,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,0,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,0,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,0,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,0,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,0,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,0,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,0,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,22,113,109,16,155,122,184,254,94,185,37,39,88,26,221,148,248,80,144,115,38,194,220,122,155,21,126,51,253,15,25,20,0,160,225,182,145,67,235,152,171,67,1,124,207,170,15,83,123,246,240,168,176,148,142,233,231,8,186,38,93,151,133,95,66,9,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,6,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,0,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,0,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,0,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,0,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,0,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,0,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,11,120,10,14,41,255,61,142,177,254,63,196,64,224,0,14,143,46,191,103,0,192,46,198,195,173,64,251,173,35,142,148,0,160,238,209,87,174,135,247,247,71,46,224,121,112,26,122,57,36,89,211,219,49,155,106,201,99,199,252,111,215,11,255,165,213,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,0,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,0,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,0,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,0,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,0,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,0,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,0,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,0,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,0,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[1,0,1,0,248,145,0,248,145,0,11,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,0,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,0,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,179,70,158,11,10,104,224,123,16,42,214,158,131,156,64,4,235,80,104,2,138,182,25,228,205,151,223,171,105,234,236,173,0,160,165,116,158,139,247,254,49,170,68,15,91,162,161,62,160,6,249,129,106,178,2,115,9,14,142,62,53,170,127,136,53,246,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,0,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[1,0,1,0,248,81,0,248,81,0,8,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,0,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,41,122,139,195,252,11,85,53,122,170,39,172,8,39,29,83,69,64,178,138,199,190,231,92,223,125,154,186,235,120,104,102,0,160,74,22,132,110,223,6,51,194,83,209,210,85,189,59,23,107,148,190,32,50,163,100,142,104,242,185,109,43,71,122,110,67,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[1,0,1,0,248,81,0,248,81,0,12,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,0,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,119,112,103,117,121,255,157,192,83,91,44,31,253,43,105,59,219,129,193,146,21,133,101,43,236,205,229,86,87,91,66,252,0,160,141,100,78,113,237,145,113,89,70,14,78,206,48,14,80,218,70,221,199,79,174,60,220,107,96,144,43,18,51,135,218,126,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,6],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4],[0,0,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,18],[184,70,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,68,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,7],[184,70,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,68,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,8],[0,160,53,203,234,79,145,82,155,67,90,65,188,199,39,235,164,30,181,122,126,243,25,253,115,22,82,102,179,140,10,155,162,255,0,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,9],[0,160,188,110,180,112,46,228,183,149,153,213,233,172,60,165,192,142,95,173,66,254,53,126,194,240,94,145,108,77,127,201,225,185,0,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,11],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,10],[1,0,1,0,248,81,0,248,81,0,1,1,0,11,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,80,90,222,110,109,11,60,70,62,54,96,68,136,32,251,73,11,145,37,204,201,177,59,4,177,45,197,186,81,171,201,54,0,160,80,90,222,110,109,11,60,70,62,54,96,68,136,32,251,73,11,145,37,204,201,177,59,4,177,45,197,186,81,171,201,54,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,117,254,248,169,140,212,202,48,190,248,66,108,226,49,13,176,213,221,44,93,158,12,29,42,13,71,21,208,116,159,193,173,0,160,117,254,248,169,140,212,202,48,190,248,66,108,226,49,13,176,213,221,44,93,158,12,29,42,13,71,21,208,116,159,193,173,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[226,27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,217,126,56,112,222,29,194,80,17,187,144,67,169,202,198,186,147,107,226,126,75,125,32,62,50,189,225,43,23,89,132,168,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,217,126,56,112,222,29,194,80,17,187,144,67,169,202,198,186,147,107,226,126,75,125,32,62,50,189,225,43,23,89,132,168,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[227,161,32,187,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,2],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,13],[226,160,32,14,45,82,118,18,7,59,38,238,205,253,113,126,106,50,12,244,75,74,250,194,176,115,45,159,203,226,183,250,12,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3],[17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,14],[226,160,32,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,15],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,19],[249,2,17,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,160,198,110,59,110,207,162,15,138,151,80,193,238,182,30,35,42,168,192,180,204,238,61,99,82,32,113,75,76,38,31,245,168,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,128,5],[249,2,17,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,160,208,11,7,160,57,118,105,130,12,148,160,224,101,79,108,119,75,73,27,251,23,112,202,194,98,232,67,35,41,20,109,227,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,128,5],[249,2,17,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,160,66,160,223,51,184,103,51,48,79,182,55,124,160,55,136,72,34,106,234,196,136,142,67,163,253,247,97,56,227,113,81,112,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,128,5],[249,2,17,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,160,156,207,34,126,96,200,143,86,98,67,48,239,210,146,94,107,198,11,34,45,151,240,146,143,132,124,18,87,19,78,100,125,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,128,5],[249,2,17,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,160,68,171,218,249,64,4,214,12,108,176,191,110,229,129,30,147,162,111,141,248,90,65,72,139,199,122,223,7,22,19,86,170,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,128,5],[249,2,17,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,160,139,236,208,88,153,113,82,137,105,145,232,206,194,251,94,134,60,159,209,170,140,223,189,13,150,246,4,251,15,48,51,104,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,128,5],[249,2,17,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,160,154,52,165,162,92,151,34,100,231,147,116,21,226,254,143,170,231,209,154,231,199,183,20,105,49,183,6,201,128,11,16,232,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,128,5],[249,2,17,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,160,159,130,229,165,212,147,78,44,146,124,254,74,180,62,107,231,41,115,95,72,27,6,25,183,104,151,116,137,84,204,53,189,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,128,5],[249,2,17,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,160,22,113,109,16,155,122,184,254,94,185,37,39,88,26,221,148,248,80,144,115,38,194,220,122,155,21,126,51,253,15,25,20,128,5],[249,2,17,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,160,225,182,145,67,235,152,171,67,1,124,207,170,15,83,123,246,240,168,176,148,142,233,231,8,186,38,93,151,133,95,66,9,128,5],[249,2,17,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,160,11,120,10,14,41,255,61,142,177,254,63,196,64,224,0,14,143,46,191,103,0,192,46,198,195,173,64,251,173,35,142,148,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,128,5],[249,2,17,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,160,238,209,87,174,135,247,247,71,46,224,121,112,26,122,57,36,89,211,219,49,155,106,201,99,199,252,111,215,11,255,165,213,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,128,5],[248,145,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,128,128,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,128,128,128,128,128,128,128,160,179,70,158,11,10,104,224,123,16,42,214,158,131,156,64,4,235,80,104,2,138,182,25,228,205,151,223,171,105,234,236,173,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,128,128,128,128,5],[248,145,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,128,128,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,128,128,128,128,128,128,128,160,165,116,158,139,247,254,49,170,68,15,91,162,161,62,160,6,249,129,106,178,2,115,9,14,142,62,53,170,127,136,53,246,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,160,41,122,139,195,252,11,85,53,122,170,39,172,8,39,29,83,69,64,178,138,199,190,231,92,223,125,154,186,235,120,104,102,128,128,128,128,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,160,74,22,132,110,223,6,51,194,83,209,210,85,189,59,23,107,148,190,32,50,163,100,142,104,242,185,109,43,71,122,110,67,128,128,128,128,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,128,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,128,128,128,160,119,112,103,117,121,255,157,192,83,91,44,31,253,43,105,59,219,129,193,146,21,133,101,43,236,205,229,86,87,91,66,252,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,128,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,128,128,128,160,141,100,78,113,237,145,113,89,70,14,78,206,48,14,80,218,70,221,199,79,174,60,220,107,96,144,43,18,51,135,218,126,128,128,128,128,5],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,184,70,248,68,128,128,160,53,203,234,79,145,82,155,67,90,65,188,199,39,235,164,30,181,122,126,243,25,253,115,22,82,102,179,140,10,155,162,255,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,5],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,184,70,248,68,128,128,160,188,110,180,112,46,228,183,149,153,213,233,172,60,165,192,142,95,173,66,254,53,126,194,240,94,145,108,77,127,201,225,185,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,5],[226,27,160,217,126,56,112,222,29,194,80,17,187,144,67,169,202,198,186,147,107,226,126,75,125,32,62,50,189,225,43,23,89,132,168,5],[248,81,128,160,80,90,222,110,109,11,60,70,62,54,96,68,136,32,251,73,11,145,37,204,201,177,59,4,177,45,197,186,81,171,201,54,128,128,128,128,128,128,128,128,128,160,117,254,248,169,140,212,202,48,190,248,66,108,226,49,13,176,213,221,44,93,158,12,29,42,13,71,21,208,116,159,193,173,128,128,128,128,128,5],[227,161,32,187,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,1,5],[226,160,32,14,45,82,118,18,7,59,38,238,205,253,113,126,106,50,12,244,75,74,250,194,176,115,45,159,203,226,183,250,12,246,17,5],[226,160,32,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,1,5]]"; \ No newline at end of file +const debug_file: &'static str = "[[0,1,0,1,249,2,17,249,2,17,13,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0],[0,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,0,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,0,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,0,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,0,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,0,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,0,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,0,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,0,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,0,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,0,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,0,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,0,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,0,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,198,110,59,110,207,162,15,138,151,80,193,238,182,30,35,42,168,192,180,204,238,61,99,82,32,113,75,76,38,31,245,168,0,160,208,11,7,160,57,118,105,130,12,148,160,224,101,79,108,119,75,73,27,251,23,112,202,194,98,232,67,35,41,20,109,227,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,0,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,0,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,17],[0,1,0,1,249,2,17,249,2,17,14,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,0,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,0,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,0,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,0,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,0,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,0,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,0,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,0,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,0,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,0,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,0,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,0,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,0,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,0,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,66,160,223,51,184,103,51,48,79,182,55,124,160,55,136,72,34,106,234,196,136,142,67,163,253,247,97,56,227,113,81,112,0,160,156,207,34,126,96,200,143,86,98,67,48,239,210,146,94,107,198,11,34,45,151,240,146,143,132,124,18,87,19,78,100,125,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,0,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,7,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,0,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,0,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,0,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,0,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,0,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,0,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,0,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,68,171,218,249,64,4,214,12,108,176,191,110,229,129,30,147,162,111,141,248,90,65,72,139,199,122,223,7,22,19,86,170,0,160,139,236,208,88,153,113,82,137,105,145,232,206,194,251,94,134,60,159,209,170,140,223,189,13,150,246,4,251,15,48,51,104,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,0,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,0,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,0,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,0,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,0,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,0,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,0,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,0,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,8,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,0,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,0,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,0,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,0,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,0,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,0,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,0,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,0,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,154,52,165,162,92,151,34,100,231,147,116,21,226,254,143,170,231,209,154,231,199,183,20,105,49,183,6,201,128,11,16,232,0,160,159,130,229,165,212,147,78,44,146,124,254,74,180,62,107,231,41,115,95,72,27,6,25,183,104,151,116,137,84,204,53,189,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,0,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,0,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,0,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,0,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,0,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,0,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,0,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,15,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,0,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,0,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,0,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,0,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,0,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,0,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,0,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,0,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,0,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,0,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,0,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,0,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,0,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,0,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,0,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,22,113,109,16,155,122,184,254,94,185,37,39,88,26,221,148,248,80,144,115,38,194,220,122,155,21,126,51,253,15,25,20,0,160,225,182,145,67,235,152,171,67,1,124,207,170,15,83,123,246,240,168,176,148,142,233,231,8,186,38,93,151,133,95,66,9,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[0,1,0,1,249,2,17,249,2,17,6,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,0,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,0,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,0,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,0,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,0,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,0,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,11,120,10,14,41,255,61,142,177,254,63,196,64,224,0,14,143,46,191,103,0,192,46,198,195,173,64,251,173,35,142,148,0,160,238,209,87,174,135,247,247,71,46,224,121,112,26,122,57,36,89,211,219,49,155,106,201,99,199,252,111,215,11,255,165,213,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,0,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,0,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,0,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,0,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,0,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,0,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,0,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,0,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,0,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[1,0,1,0,248,145,0,248,145,0,11,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,0,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,0,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,179,70,158,11,10,104,224,123,16,42,214,158,131,156,64,4,235,80,104,2,138,182,25,228,205,151,223,171,105,234,236,173,0,160,165,116,158,139,247,254,49,170,68,15,91,162,161,62,160,6,249,129,106,178,2,115,9,14,142,62,53,170,127,136,53,246,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,0,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[1,0,1,0,248,81,0,248,81,0,8,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,0,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,41,122,139,195,252,11,85,53,122,170,39,172,8,39,29,83,69,64,178,138,199,190,231,92,223,125,154,186,235,120,104,102,0,160,74,22,132,110,223,6,51,194,83,209,210,85,189,59,23,107,148,190,32,50,163,100,142,104,242,185,109,43,71,122,110,67,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[1,0,1,0,248,81,0,248,81,0,12,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,0,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,119,112,103,117,121,255,157,192,83,91,44,31,253,43,105,59,219,129,193,146,21,133,101,43,236,205,229,86,87,91,66,252,0,160,141,100,78,113,237,145,113,89,70,14,78,206,48,14,80,218,70,221,199,79,174,60,220,107,96,144,43,18,51,135,218,126,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,6],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4],[0,0,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,18],[184,70,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,68,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,7],[184,70,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,68,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,8],[0,160,53,203,234,79,145,82,155,67,90,65,188,199,39,235,164,30,181,122,126,243,25,253,115,22,82,102,179,140,10,155,162,255,0,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,9],[0,160,188,110,180,112,46,228,183,149,153,213,233,172,60,165,192,142,95,173,66,254,53,126,194,240,94,145,108,77,127,201,225,185,0,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,11],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,10],[1,0,1,0,248,81,0,248,81,0,1,1,0,11,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,80,90,222,110,109,11,60,70,62,54,96,68,136,32,251,73,11,145,37,204,201,177,59,4,177,45,197,186,81,171,201,54,0,160,80,90,222,110,109,11,60,70,62,54,96,68,136,32,251,73,11,145,37,204,201,177,59,4,177,45,197,186,81,171,201,54,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,160,117,254,248,169,140,212,202,48,190,248,66,108,226,49,13,176,213,221,44,93,158,12,29,42,13,71,21,208,116,159,193,173,0,160,117,254,248,169,140,212,202,48,190,248,66,108,226,49,13,176,213,221,44,93,158,12,29,42,13,71,21,208,116,159,193,173,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],[226,27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,217,126,56,112,222,29,194,80,17,187,144,67,169,202,198,186,147,107,226,126,75,125,32,62,50,189,225,43,23,89,132,168,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,217,126,56,112,222,29,194,80,17,187,144,67,169,202,198,186,147,107,226,126,75,125,32,62,50,189,225,43,23,89,132,168,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,17],[227,161,32,187,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,2],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,13],[226,160,32,14,45,82,118,18,7,59,38,238,205,253,113,126,106,50,12,244,75,74,250,194,176,115,45,159,203,226,183,250,12,246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3],[17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,14],[226,160,32,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,15],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,143,4,93,60,93,242,62,224,221,187,136,15,32,210,22,238,152,245,194,205,214,168,192,202,35,51,216,91,164,166,248,37,34,234,18,21,213,199,151,55,56,71,97,141,132,147,29,245,89,166,167,28,253,151,151,184,228,239,85,42,79,172,110,222,120,246,184,198,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,19],[249,2,17,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,160,198,110,59,110,207,162,15,138,151,80,193,238,182,30,35,42,168,192,180,204,238,61,99,82,32,113,75,76,38,31,245,168,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,128,5],[249,2,17,160,215,178,43,142,72,221,147,48,230,157,99,126,109,240,144,184,54,167,1,19,157,71,126,226,97,100,220,221,118,5,202,114,160,195,19,38,251,242,179,135,46,118,82,177,213,78,156,167,171,134,95,6,233,153,168,219,176,131,34,215,213,95,252,168,165,160,242,119,75,182,209,50,158,172,168,239,218,202,172,144,155,94,44,154,149,92,253,83,150,12,4,176,33,46,25,36,170,225,160,156,18,160,254,15,159,132,100,9,112,178,98,98,93,76,54,189,166,63,219,45,193,25,238,218,78,235,150,206,67,252,253,160,100,75,99,34,122,170,85,172,143,62,172,142,154,219,40,105,162,136,113,194,41,38,129,211,105,114,94,62,145,244,97,170,160,229,94,177,9,226,34,180,156,33,249,119,163,74,194,218,172,92,90,13,44,22,231,5,100,72,203,19,192,62,46,34,34,160,15,175,179,52,244,84,197,105,112,43,252,115,186,76,237,251,88,5,62,201,157,9,7,153,100,224,202,249,250,183,125,248,160,14,229,239,45,75,116,39,109,41,89,200,43,18,94,204,133,62,175,23,200,68,93,170,95,36,226,233,183,66,98,37,184,160,6,197,49,201,57,39,248,81,26,196,11,167,230,243,100,223,97,38,20,1,226,39,180,161,172,204,67,80,173,223,89,42,160,3,131,195,206,124,22,207,14,142,91,216,135,77,202,69,1,53,115,223,85,52,95,43,227,237,82,138,95,93,70,227,232,160,98,109,64,32,201,140,205,221,164,1,209,57,84,209,249,108,87,101,70,12,37,160,114,139,27,145,104,130,62,183,150,108,160,69,221,169,92,165,83,34,53,123,93,55,127,206,167,112,175,13,233,196,118,68,137,156,246,219,49,159,137,25,37,30,157,160,39,24,29,240,236,191,237,195,74,255,251,61,19,232,218,181,111,83,69,125,70,208,135,182,81,0,125,85,38,21,25,11,160,208,11,7,160,57,118,105,130,12,148,160,224,101,79,108,119,75,73,27,251,23,112,202,194,98,232,67,35,41,20,109,227,160,238,147,22,82,116,71,41,238,84,0,62,40,0,153,205,90,194,234,61,255,205,197,55,0,41,239,197,174,219,163,6,130,160,22,99,129,222,131,163,115,40,32,94,210,97,181,141,77,173,9,184,214,164,50,44,139,113,241,255,7,213,43,8,145,41,128,5],[249,2,17,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,160,66,160,223,51,184,103,51,48,79,182,55,124,160,55,136,72,34,106,234,196,136,142,67,163,253,247,97,56,227,113,81,112,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,128,5],[249,2,17,160,8,82,228,160,236,167,211,34,103,186,143,82,159,227,56,83,90,137,189,168,42,104,95,52,183,148,255,215,136,52,73,231,160,84,120,210,249,75,139,182,38,44,242,80,181,2,165,43,146,17,155,131,187,29,254,176,179,119,232,197,70,165,227,43,64,160,194,12,142,1,144,174,252,71,147,52,115,101,189,153,208,184,182,11,61,226,102,6,152,102,88,19,198,73,12,11,50,155,160,59,143,74,53,247,240,239,138,121,223,75,218,127,28,117,171,91,193,129,250,204,248,51,157,35,23,2,179,196,54,170,46,160,157,90,51,248,241,223,224,87,67,255,188,60,98,138,52,58,248,0,103,191,25,93,87,196,48,17,193,91,196,174,84,68,160,37,36,38,176,196,202,58,86,76,239,236,180,113,34,151,66,223,175,221,244,2,135,167,81,134,210,144,189,210,100,169,46,160,246,249,160,14,73,156,38,98,129,209,255,124,122,147,16,52,200,78,213,139,162,204,164,40,13,165,111,148,15,31,205,20,160,196,63,137,26,203,165,150,154,136,200,90,27,244,146,124,13,112,147,170,137,82,86,194,212,83,213,250,77,122,235,81,108,160,23,72,191,114,109,241,153,152,28,181,114,222,27,12,163,170,167,243,68,76,13,193,8,43,209,0,251,139,245,110,12,200,160,162,242,12,159,239,231,230,109,155,112,235,20,28,190,163,94,48,238,186,27,192,248,95,119,246,213,205,3,106,83,34,57,160,98,128,143,73,77,78,229,115,157,26,53,223,153,171,114,69,45,174,24,124,45,42,137,236,225,137,107,235,241,54,22,248,160,28,67,53,54,154,2,91,141,228,22,200,27,178,90,210,209,195,121,126,22,72,172,98,207,112,253,149,202,240,32,170,32,160,77,183,169,108,222,80,160,149,46,20,80,223,164,78,82,196,134,47,182,103,106,44,118,54,158,56,222,196,13,46,87,30,160,105,251,188,224,72,188,242,142,5,202,96,164,238,163,221,166,92,66,41,9,240,19,219,203,186,100,64,23,163,241,100,34,160,156,207,34,126,96,200,143,86,98,67,48,239,210,146,94,107,198,11,34,45,151,240,146,143,132,124,18,87,19,78,100,125,160,70,28,143,53,189,11,148,71,98,61,108,214,101,187,1,240,58,157,104,142,179,155,185,249,28,6,177,21,81,199,24,148,128,5],[249,2,17,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,160,68,171,218,249,64,4,214,12,108,176,191,110,229,129,30,147,162,111,141,248,90,65,72,139,199,122,223,7,22,19,86,170,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,128,5],[249,2,17,160,28,181,216,79,148,37,18,33,67,109,190,5,141,78,14,125,126,101,243,129,183,164,252,246,188,222,123,209,72,162,91,222,160,127,197,158,74,119,72,230,12,125,176,108,3,178,158,78,4,13,240,18,19,137,90,52,126,5,105,198,181,219,43,179,65,160,46,9,75,129,71,206,112,222,185,139,165,36,36,211,46,89,3,55,130,67,49,169,124,254,145,239,59,68,181,39,14,11,160,195,204,36,121,188,76,85,107,153,228,243,120,219,164,214,149,84,154,93,6,211,138,212,126,99,0,69,93,78,143,107,125,160,24,229,27,106,208,179,138,207,189,75,247,237,254,184,165,211,163,77,102,247,171,142,38,241,105,73,81,97,179,89,41,94,160,69,128,196,179,31,166,62,236,4,126,133,123,72,78,7,98,91,97,202,41,213,219,83,161,250,44,62,218,202,202,95,85,160,122,138,244,235,222,164,181,224,94,192,101,250,2,159,226,141,139,49,161,182,189,7,58,131,181,174,22,234,166,219,45,89,160,139,236,208,88,153,113,82,137,105,145,232,206,194,251,94,134,60,159,209,170,140,223,189,13,150,246,4,251,15,48,51,104,160,44,69,190,86,52,17,185,107,193,188,16,167,86,61,125,177,50,240,102,96,66,255,44,165,212,175,229,245,163,179,105,42,160,236,64,240,32,156,40,69,140,109,160,30,103,177,225,161,137,199,148,118,155,53,110,110,30,88,113,102,249,146,51,146,64,160,13,42,32,122,82,79,121,74,202,120,184,186,33,169,210,46,107,49,203,217,253,81,204,72,172,54,254,232,169,31,66,180,160,249,124,106,89,244,190,54,102,66,217,238,184,69,54,42,49,217,172,209,72,171,109,172,162,227,248,91,39,84,60,12,50,160,71,37,113,174,70,115,139,170,17,161,226,89,54,206,220,216,124,175,149,45,37,207,232,200,177,22,55,13,211,27,128,159,160,230,15,33,183,4,214,67,103,40,12,190,159,2,136,107,119,218,240,254,147,196,64,54,80,160,212,123,210,158,221,177,79,160,81,251,139,38,98,234,236,80,109,218,180,81,152,102,115,99,187,67,51,108,50,176,183,19,208,120,5,0,187,173,25,231,160,91,147,3,93,139,16,136,76,22,19,70,240,73,156,182,34,44,29,125,2,237,83,117,238,18,211,207,207,135,137,154,42,128,5],[249,2,17,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,160,154,52,165,162,92,151,34,100,231,147,116,21,226,254,143,170,231,209,154,231,199,183,20,105,49,183,6,201,128,11,16,232,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,128,5],[249,2,17,160,69,240,19,94,201,88,43,0,240,10,245,154,168,230,212,225,91,127,174,54,14,224,25,37,243,187,212,166,69,13,214,210,160,177,114,250,165,145,160,168,147,73,120,43,40,134,214,183,54,244,101,72,160,70,135,200,49,243,43,70,171,72,51,232,228,160,90,126,11,244,198,223,145,243,175,101,108,33,157,37,38,154,185,230,186,210,117,24,108,72,19,80,181,127,12,80,114,155,160,78,180,178,103,237,5,128,118,135,163,125,238,136,63,98,140,254,188,122,80,58,140,165,170,224,23,27,182,205,122,170,222,160,147,155,221,36,17,65,128,167,31,175,127,179,216,23,237,245,34,236,18,107,89,51,94,106,56,12,20,74,110,149,105,207,160,15,28,106,136,34,61,58,29,173,134,221,145,72,139,220,37,191,242,241,153,92,130,98,238,20,55,147,180,1,187,72,252,160,101,28,170,8,68,246,158,179,253,114,81,91,184,162,73,227,249,57,19,194,215,111,218,79,13,14,253,173,39,152,43,12,160,101,42,250,164,65,159,130,225,36,154,115,39,124,11,13,239,251,223,52,197,47,222,172,222,166,233,67,63,237,150,142,147,160,159,130,229,165,212,147,78,44,146,124,254,74,180,62,107,231,41,115,95,72,27,6,25,183,104,151,116,137,84,204,53,189,160,207,152,180,142,136,28,103,23,207,112,171,22,117,189,204,168,205,65,250,82,77,7,189,224,17,6,107,65,153,196,51,115,160,236,88,60,30,32,14,250,185,46,86,72,75,128,6,144,52,126,176,244,75,144,130,37,202,71,232,43,210,154,98,86,223,160,96,182,165,136,194,214,172,207,177,61,121,19,192,171,159,135,101,154,232,237,19,245,224,68,199,165,13,58,252,78,199,233,160,12,4,159,3,157,220,175,164,62,180,206,33,25,128,18,219,176,112,152,50,85,173,6,36,29,160,252,251,57,179,108,55,160,178,76,4,254,107,101,118,101,72,242,165,126,184,251,148,195,179,2,253,197,81,175,197,164,92,27,185,14,251,174,58,27,160,22,172,44,183,17,252,57,28,189,212,135,200,167,233,149,136,217,169,139,57,170,76,181,203,160,31,77,109,109,107,10,90,160,129,79,119,239,14,8,139,99,226,197,245,208,38,121,249,69,188,180,205,60,221,179,140,56,207,45,139,57,243,129,240,114,128,5],[249,2,17,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,160,22,113,109,16,155,122,184,254,94,185,37,39,88,26,221,148,248,80,144,115,38,194,220,122,155,21,126,51,253,15,25,20,128,5],[249,2,17,160,135,143,213,43,63,194,224,22,73,85,234,57,32,136,196,138,144,25,14,53,225,60,238,148,1,160,19,151,227,159,49,183,160,2,29,173,25,96,174,9,182,182,173,122,125,236,76,251,176,5,245,88,46,126,30,246,22,125,175,153,67,210,235,64,8,160,28,189,158,3,1,129,244,212,210,46,30,196,172,161,20,195,243,158,211,25,117,74,30,254,41,187,49,138,192,150,52,17,160,239,95,253,44,136,34,194,144,153,28,242,248,222,215,110,46,230,231,27,170,229,101,3,204,99,204,208,118,114,93,83,110,160,7,159,235,95,194,73,95,243,22,246,19,38,251,43,141,128,8,190,255,67,153,158,211,166,139,252,168,40,63,188,205,95,160,238,34,57,54,115,74,242,131,214,151,182,44,143,250,245,22,211,176,245,204,227,75,151,108,89,28,167,182,144,17,21,92,160,110,82,232,2,216,240,70,229,147,241,71,82,114,9,73,189,84,16,27,151,65,30,46,28,117,225,27,149,182,208,51,159,160,155,189,91,3,70,25,27,41,10,49,193,196,22,63,42,36,133,91,199,238,35,240,242,161,252,0,183,96,230,193,68,235,160,254,225,94,214,235,151,75,30,231,42,49,211,232,190,3,200,245,38,113,10,27,249,194,216,43,216,49,187,170,57,95,202,160,46,121,163,72,94,105,150,192,89,117,100,231,44,8,94,84,224,173,10,128,89,76,114,29,254,213,243,87,146,33,249,173,160,182,172,93,250,183,64,112,173,6,173,19,151,175,126,144,31,75,142,43,92,76,129,21,185,125,95,55,38,17,68,4,54,160,101,105,235,77,175,160,222,72,81,15,175,2,24,88,227,4,106,202,82,46,144,46,234,120,227,124,28,91,186,48,175,127,160,107,199,179,225,2,21,145,210,96,156,115,9,90,72,224,6,92,117,170,140,51,4,185,247,179,137,241,5,125,9,215,216,160,174,1,41,24,170,64,96,231,200,121,39,32,55,169,45,50,38,91,148,155,128,81,65,213,115,175,165,99,88,151,50,116,160,175,48,34,68,54,34,13,191,110,96,44,135,10,240,213,61,134,176,37,129,8,182,235,41,95,208,183,87,202,245,167,238,160,225,182,145,67,235,152,171,67,1,124,207,170,15,83,123,246,240,168,176,148,142,233,231,8,186,38,93,151,133,95,66,9,128,5],[249,2,17,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,160,11,120,10,14,41,255,61,142,177,254,63,196,64,224,0,14,143,46,191,103,0,192,46,198,195,173,64,251,173,35,142,148,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,128,5],[249,2,17,160,240,112,44,72,20,92,16,226,238,153,16,125,149,130,241,10,60,36,30,150,251,167,132,127,195,28,146,162,13,131,27,104,160,138,1,235,206,4,16,156,100,75,197,42,86,62,127,48,60,191,73,198,101,215,247,43,217,243,100,129,241,204,220,255,148,160,236,7,15,200,76,214,175,181,111,16,213,238,208,13,129,154,34,238,224,26,140,170,215,20,77,216,157,80,95,241,66,5,160,111,209,247,4,184,241,13,91,12,184,243,229,45,164,245,146,134,164,11,3,131,241,44,248,165,88,52,99,193,196,218,253,160,229,51,62,185,89,4,163,95,20,136,220,188,187,42,151,97,47,27,99,112,96,146,185,113,108,59,23,95,91,242,168,231,160,225,30,140,67,250,53,232,133,42,214,15,162,35,11,145,22,0,220,112,181,254,56,69,155,136,93,110,187,205,140,249,25,160,238,209,87,174,135,247,247,71,46,224,121,112,26,122,57,36,89,211,219,49,155,106,201,99,199,252,111,215,11,255,165,213,160,70,32,6,139,201,80,250,209,245,47,57,130,174,10,207,204,234,130,173,235,16,22,234,52,196,221,80,211,111,246,11,181,160,53,254,22,227,103,204,187,138,101,229,227,171,9,232,13,105,208,170,117,193,81,106,4,200,93,89,129,132,160,158,41,161,160,186,224,186,141,73,213,194,212,99,82,80,83,63,102,245,177,171,65,255,49,96,123,226,247,84,252,59,154,66,254,96,67,160,228,118,98,158,169,240,61,44,106,136,219,101,77,16,63,14,204,240,38,190,219,80,247,204,97,190,78,228,105,224,67,95,160,191,245,233,165,127,57,224,124,150,65,148,214,187,48,38,122,66,30,227,50,65,101,40,51,58,89,7,228,45,27,112,166,160,47,164,236,183,87,115,134,179,223,254,239,90,133,214,85,54,22,167,1,92,153,195,176,38,176,219,172,7,191,23,55,122,160,215,6,239,231,6,41,80,135,222,236,3,134,0,18,22,209,211,166,221,135,184,73,179,164,230,223,10,101,145,99,150,96,160,63,103,2,71,244,232,117,254,117,119,209,72,224,148,116,41,203,106,207,131,104,246,110,140,246,162,32,29,20,147,74,227,160,235,217,213,36,97,57,33,70,140,131,115,203,161,172,152,58,3,51,31,34,188,42,244,174,85,218,174,183,39,13,100,120,128,5],[248,145,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,128,128,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,128,128,128,128,128,128,128,160,179,70,158,11,10,104,224,123,16,42,214,158,131,156,64,4,235,80,104,2,138,182,25,228,205,151,223,171,105,234,236,173,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,128,128,128,128,5],[248,145,160,73,208,126,64,185,124,226,254,200,156,38,73,116,28,98,39,159,197,2,205,192,137,219,133,250,225,251,164,26,205,18,81,128,128,160,4,223,126,85,68,106,50,147,247,249,222,159,87,179,121,227,15,254,85,49,250,43,16,96,127,220,135,236,178,131,92,58,128,128,128,128,128,128,128,160,165,116,158,139,247,254,49,170,68,15,91,162,161,62,160,6,249,129,106,178,2,115,9,14,142,62,53,170,127,136,53,246,160,1,162,74,47,57,45,87,11,81,221,83,234,28,100,214,43,52,204,21,204,51,217,33,45,57,156,224,74,233,176,82,221,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,160,41,122,139,195,252,11,85,53,122,170,39,172,8,39,29,83,69,64,178,138,199,190,231,92,223,125,154,186,235,120,104,102,128,128,128,128,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,160,222,170,68,108,117,176,212,174,211,39,185,133,117,19,156,115,206,166,217,135,198,124,199,163,157,194,82,167,202,167,62,219,160,74,22,132,110,223,6,51,194,83,209,210,85,189,59,23,107,148,190,32,50,163,100,142,104,242,185,109,43,71,122,110,67,128,128,128,128,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,128,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,128,128,128,160,119,112,103,117,121,255,157,192,83,91,44,31,253,43,105,59,219,129,193,146,21,133,101,43,236,205,229,86,87,91,66,252,128,128,128,128,5],[248,81,128,128,128,128,128,128,128,128,160,160,9,113,129,125,176,108,165,204,52,73,31,120,48,145,70,180,84,104,164,114,187,197,135,250,222,46,181,93,217,99,207,128,128,128,160,141,100,78,113,237,145,113,89,70,14,78,206,48,14,80,218,70,221,199,79,174,60,220,107,96,144,43,18,51,135,218,126,128,128,128,128,5],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,184,70,248,68,128,128,160,53,203,234,79,145,82,155,67,90,65,188,199,39,235,164,30,181,122,126,243,25,253,115,22,82,102,179,140,10,155,162,255,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,5],[248,101,156,54,61,33,45,197,58,196,129,133,210,48,128,228,223,90,105,143,227,55,221,219,111,227,231,120,76,129,184,184,70,248,68,128,128,160,188,110,180,112,46,228,183,149,153,213,233,172,60,165,192,142,95,173,66,254,53,126,194,240,94,145,108,77,127,201,225,185,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112,5],[226,27,160,217,126,56,112,222,29,194,80,17,187,144,67,169,202,198,186,147,107,226,126,75,125,32,62,50,189,225,43,23,89,132,168,5],[248,81,128,160,80,90,222,110,109,11,60,70,62,54,96,68,136,32,251,73,11,145,37,204,201,177,59,4,177,45,197,186,81,171,201,54,128,128,128,128,128,128,128,128,128,160,117,254,248,169,140,212,202,48,190,248,66,108,226,49,13,176,213,221,44,93,158,12,29,42,13,71,21,208,116,159,193,173,128,128,128,128,128,5],[227,161,32,187,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,1,5],[226,160,32,14,45,82,118,18,7,59,38,238,205,253,113,126,106,50,12,244,75,74,250,194,176,115,45,159,203,226,183,250,12,246,17,5],[226,160,32,138,106,70,105,186,37,13,38,205,122,69,158,202,157,33,95,131,7,227,58,235,229,3,121,188,90,54,23,236,52,68,1,5]]"; diff --git a/zkevm-circuits/src/mpt_circuit/account_leaf.rs b/zkevm-circuits/src/mpt_circuit/account_leaf.rs index 140484e04b..f788d96645 100644 --- a/zkevm-circuits/src/mpt_circuit/account_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/account_leaf.rs @@ -181,6 +181,7 @@ impl AccountLeafConfig { // Check if the account is in its parent. // Check is skipped for placeholder leaves which are dummy leaves ifx! {not!(and::expr(&[not!(config.parent_data[is_s.idx()].is_placeholder), config.is_in_empty_trie[is_s.idx()].expr()])) => { + // cb.lookup_keccak(1.expr(), leaf_rlc.clone(), rlp_key.rlp_list.num_bytes(), config.parent_data[is_s.idx()].rlc.expr()); require!((1, leaf_rlc, rlp_key.rlp_list.num_bytes(), config.parent_data[is_s.idx()].rlc) => @"keccak"); }} @@ -360,7 +361,7 @@ impl AccountLeafConfig { pub fn assign>( &self, - region: &mut Region, + cached_region: &mut CachedRegion<'_, '_, F, S>, challenges: &S, mpt_config: &MPTConfig, pv: &mut MPTState, @@ -368,10 +369,6 @@ impl AccountLeafConfig { node: &Node, rlp_values: &[RLPItemWitness], ) -> Result<(), Error> { - let mut region = CachedRegion::new( - region, - challenges - ); let account = &node.account.clone().unwrap(); let key_items = [ @@ -399,7 +396,7 @@ impl AccountLeafConfig { let main_data = self.main_data - .witness_load(&mut region, offset, &pv.memory[main_memory()], 0)?; + .witness_load(cached_region, offset, &pv.memory[main_memory()], 0)?; // Key let mut key_rlc = vec![0.scalar(); 2]; @@ -414,39 +411,39 @@ impl AccountLeafConfig { .iter() .zip(account.value_rlp_bytes[is_s.idx()].iter()) { - cell.assign(&mut region, offset, byte.scalar())?; + cell.assign(cached_region, offset, byte.scalar())?; } for (cell, byte) in self.value_list_rlp_bytes[is_s.idx()] .iter() .zip(account.value_list_rlp_bytes[is_s.idx()].iter()) { - cell.assign(&mut region, offset, byte.scalar())?; + cell.assign(cached_region, offset, byte.scalar())?; } key_data[is_s.idx()] = self.key_data[is_s.idx()].witness_load( - &mut region, + cached_region, offset, &mut pv.memory[key_memory(is_s)], 0, )?; parent_data[is_s.idx()] = self.parent_data[is_s.idx()].witness_load( - &mut region, + cached_region, offset, &mut pv.memory[parent_memory(is_s)], 0, )?; self.is_in_empty_trie[is_s.idx()].assign( - &mut region, + cached_region, offset, parent_data[is_s.idx()].rlc, pv.r, )?; let rlp_key_witness = self.rlp_key[is_s.idx()].assign( - &mut region, + cached_region, offset, &account.list_rlp_bytes[is_s.idx()], &key_items[is_s.idx()], @@ -467,7 +464,7 @@ impl AccountLeafConfig { // Update key and parent state KeyData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[key_memory(is_s)], F::zero(), @@ -478,7 +475,7 @@ impl AccountLeafConfig { 0, )?; ParentData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[parent_memory(is_s)], storage_rlc[is_s.idx()], @@ -490,7 +487,7 @@ impl AccountLeafConfig { // Anything following this node is below the account MainData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[main_memory()], main_data.proof_type, @@ -502,37 +499,37 @@ impl AccountLeafConfig { // Proof types let is_non_existing_proof = self.is_non_existing_account_proof.assign( - &mut region, + cached_region, offset, main_data.proof_type.scalar(), MPTProofType::AccountDoesNotExist.scalar(), )? == true.scalar(); let is_account_delete_mod = self.is_account_delete_mod.assign( - &mut region, + cached_region, offset, main_data.proof_type.scalar(), MPTProofType::AccountDestructed.scalar(), )? == true.scalar(); let is_nonce_mod = self.is_nonce_mod.assign( - &mut region, + cached_region, offset, main_data.proof_type.scalar(), MPTProofType::NonceChanged.scalar(), )? == true.scalar(); let is_balance_mod = self.is_balance_mod.assign( - &mut region, + cached_region, offset, main_data.proof_type.scalar(), MPTProofType::BalanceChanged.scalar(), )? == true.scalar(); let is_storage_mod = self.is_storage_mod.assign( - &mut region, + cached_region, offset, main_data.proof_type.scalar(), MPTProofType::StorageChanged.scalar(), )? == true.scalar(); let is_codehash_mod = self.is_codehash_mod.assign( - &mut region, + cached_region, offset, main_data.proof_type.scalar(), MPTProofType::CodeHashExists.scalar(), @@ -540,7 +537,7 @@ impl AccountLeafConfig { // Drifted leaf handling self.drifted.assign( - &mut region, + cached_region, offset, &parent_data, &account.drifted_rlp_bytes, @@ -550,7 +547,7 @@ impl AccountLeafConfig { // Wrong leaf handling self.wrong.assign( - &mut region, + cached_region, offset, is_non_existing_proof, &key_rlc, @@ -578,7 +575,7 @@ impl AccountLeafConfig { (MPTProofType::Disabled, vec![0.scalar(); 2]) }; mpt_config.mpt_table.assign_cached( - &mut region, + cached_region, offset, &MptUpdateRow { address_rlc: Value::known(account.address.rlc_value(pv.r)), @@ -590,6 +587,8 @@ impl AccountLeafConfig { root: Value::known(main_data.root), }, )?; + //println!("{} account ====> cahced_region.advice\n {:?}", offset, cached_region.advice); + //mpt_config.assign_static_lookups(cached_region, offset); Ok(()) } diff --git a/zkevm-circuits/src/mpt_circuit/extension_branch.rs b/zkevm-circuits/src/mpt_circuit/extension_branch.rs index 6d9309fd78..304990cf93 100644 --- a/zkevm-circuits/src/mpt_circuit/extension_branch.rs +++ b/zkevm-circuits/src/mpt_circuit/extension_branch.rs @@ -183,7 +183,7 @@ impl ExtensionBranchConfig { pub(crate) fn assign>( &self, - region: &mut Region, + cached_region: &mut CachedRegion<'_, '_, F, S>, challenges: &S, mpt_config: &MPTConfig, pv: &mut MPTState, @@ -191,28 +191,24 @@ impl ExtensionBranchConfig { node: &Node, rlp_values: &[RLPItemWitness], ) -> Result<(), Error> { - let mut region = CachedRegion::new( - region, - challenges - ); let extension_branch = &node.extension_branch.clone().unwrap(); self.is_extension - .assign(&mut region, offset, extension_branch.is_extension.scalar())?; + .assign(cached_region, offset, extension_branch.is_extension.scalar())?; let key_data = self.key_data - .witness_load(&mut region, offset, &pv.memory[key_memory(true)], 0)?; + .witness_load(cached_region, offset, &pv.memory[key_memory(true)], 0)?; let mut parent_data = vec![ParentDataWitness::default(); 2]; for is_s in [true, false] { parent_data[is_s.idx()] = self.parent_data[is_s.idx()].witness_load( - &mut region, + cached_region, offset, &mut pv.memory[parent_memory(is_s)], 0, )?; self.is_placeholder[is_s.idx()].assign( - &mut region, + cached_region, offset, extension_branch.is_placeholder[is_s.idx()].scalar(), )?; @@ -226,7 +222,7 @@ impl ExtensionBranchConfig { // Extension if extension_branch.is_extension { self.extension.assign( - &mut region, + cached_region, mpt_config, pv, offset, @@ -243,7 +239,7 @@ impl ExtensionBranchConfig { // Branch let (key_rlc_post_branch, key_rlc_post_drifted, key_mult_post_branch, mod_node_hash_rlc) = self.branch.assign( - &mut region, + cached_region, mpt_config, pv, offset, @@ -260,7 +256,7 @@ impl ExtensionBranchConfig { for is_s in [true, false] { if !extension_branch.is_placeholder[is_s.idx()] { KeyData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[key_memory(is_s)], key_rlc_post_branch, @@ -271,7 +267,7 @@ impl ExtensionBranchConfig { 0, )?; ParentData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[parent_memory(is_s)], mod_node_hash_rlc[is_s.idx()], @@ -281,7 +277,7 @@ impl ExtensionBranchConfig { )?; } else { KeyData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[key_memory(is_s)], key_data.rlc, @@ -292,7 +288,7 @@ impl ExtensionBranchConfig { num_nibbles, )?; ParentData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[parent_memory(is_s)], parent_data[is_s.idx()].rlc, @@ -302,6 +298,8 @@ impl ExtensionBranchConfig { )?; } } + //println!("{} branch ====> cahced_region.advice\n {:?}", offset, cached_region.advice); + //mpt_config.assign_static_lookups(cached_region, offset); Ok(()) } diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index 6ea807908f..e5a4a4daf3 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -13,7 +13,7 @@ use crate::{ param::{EMPTY_TRIE_HASH, KEY_LEN_IN_NIBBLES, KEY_PREFIX_EVEN, KEY_TERMINAL_PREFIX_EVEN}, rlp_gadgets::{get_ext_odd_nibble, get_terminal_odd_nibble}, }, - util::Expr, + util::{Expr, Challenges}, evm_circuit::table::Table, }; use eth_types::Field; use gadgets::util::{or, pow, Scalar}; @@ -768,7 +768,7 @@ pub(crate) mod num_nibbles { key_len: Expression, is_key_odd: Expression, ) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb.base], { ifx! {is_key_odd => { key_len.expr() * 2.expr() - 1.expr() @@ -802,13 +802,19 @@ pub(crate) fn main_memory() -> String { #[derive(Clone)] pub struct MPTConstraintBuilder { pub base: ConstraintBuilder, + pub challenges: Option>>, } impl MPTConstraintBuilder { - pub(crate) fn new(max_degree: usize, cell_manager: Option>) -> Self { + pub(crate) fn new( + max_degree: usize, + challenges: Option>>, + cell_manager: Option> + ) -> Self { MPTConstraintBuilder { base: ConstraintBuilder::new(max_degree, cell_manager), + challenges, } } @@ -816,6 +822,14 @@ impl MPTConstraintBuilder { self.base.is_descr_disabled() } + pub(crate) fn push_condition(&mut self, condition: Expression) { + self.base.push_condition(condition) + } + + pub(crate) fn pop_condition(&mut self) { + self.base.pop_condition() + } + pub(crate) fn query_bool(&mut self) -> Cell { self.base.query_bool() } @@ -885,14 +899,36 @@ impl MPTConstraintBuilder { self.base.store_dynamic_table(description, tag, values) } - pub(crate) fn push_condition(&mut self, condition: Expression) { - self.base.push_condition(condition) - } + // MPT specific static lookups - pub(crate) fn pop_condition(&mut self) { - self.base.pop_condition() + pub(crate) fn lookup_keccak( + &mut self, + is_enabled: Expression, + input_rlc: Expression, + input_len: Expression, + output_rlc: Expression + ) { + let chellenge = self.challenges.as_ref().expect("Challenges unset!"); + self.base.add_static_lookup( + "keccak", + chellenge.lookup_input(), + EvmCellType::Lookup(Table::Keccak), + vec![is_enabled, input_rlc, input_len, output_rlc]); } + pub(crate) fn lookup_fixed( + &mut self, + tag: Expression, + val_1: Expression, + val_2: Expression, + ) { + let chellenge = self.challenges.as_ref().expect("Challenges unset!"); + self.base.add_static_lookup( + "fixed", + chellenge.lookup_input(), + EvmCellType::Lookup(Table::Fixed), + vec![tag, val_1, val_2]); + } } /// Returns `1` when `value == 0`, and returns `0` otherwise. @@ -1125,6 +1161,7 @@ pub struct MainRLPGadget { impl MainRLPGadget { pub(crate) fn construct(cb: &mut MPTConstraintBuilder, r: &Expression) -> Self { + println!("_________ MainRLPGadget ________"); let mut config = MainRLPGadget::default(); config.bytes = cb.query_cells::<34>().to_vec(); circuit!([meta, cb], { @@ -1147,7 +1184,13 @@ impl MainRLPGadget { require!(config.rlc_rlp => config.rlp.rlc_rlp(cb, r)); config.mult_diff = cb.query_cell(); let mult_diff = config.mult_diff.expr(); - require!((FixedTableTag::RMult, config.rlp.num_bytes(), mult_diff) => @format!("fixed")); + + println!("cb.lookup_fixed: \n\tFixedTableTag::RLen.expr(): {:?}\n\tconfig.rlp.len(): {:?}\n\tmult_diff: {:?}", + >::expr(&FixedTableTag::RMult).identifier(), config.rlp.len().identifier(), mult_diff.identifier()); + + + cb.lookup_fixed(FixedTableTag::RMult.expr(), config.rlp.num_bytes(), mult_diff.clone()); + require!((FixedTableTag::RMult, config.rlp.num_bytes(), mult_diff) => @"fixed"); // "free" input that needs to be constrained externally! config.tag = cb.query_cell(); diff --git a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs index 8eadab8e70..815430bd50 100644 --- a/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs +++ b/zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs @@ -105,7 +105,7 @@ impl RLPListGadget { /// Number of RLP bytes pub(crate) fn num_rlp_bytes(&self) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.is_short() => 1.expr(), @@ -122,7 +122,7 @@ impl RLPListGadget { /// Returns the length of the list (excluding RLP bytes) pub(crate) fn len(&self) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.is_short() => get_len_list_short::expr(self.bytes[0].expr()), @@ -139,7 +139,7 @@ impl RLPListGadget { /// Returns the rlc of only the RLP bytes pub(crate) fn rlc_rlp_only(&self, r: &Expression) -> (Expression, Expression) { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.is_short() => (self.bytes[..1].rlc(r), pow::expr(r.expr(), 1)), @@ -338,7 +338,7 @@ impl RLPValueGadget { /// Number of RLP bytes pub(crate) fn num_rlp_bytes(&self) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.is_short() => 0.expr(), @@ -350,7 +350,7 @@ impl RLPValueGadget { /// Number of bytes in total (including RLP bytes) pub(crate) fn num_bytes(&self) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.is_short() => 1.expr(), @@ -365,7 +365,7 @@ impl RLPValueGadget { /// Length of the value (excluding RLP bytes) pub(crate) fn len(&self) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.is_short() => 1.expr(), @@ -388,7 +388,7 @@ impl RLPValueGadget { } pub(crate) fn rlc_value(&self, r: &Expression) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.is_short() => { @@ -592,7 +592,7 @@ impl RLPItemGadget { // Single RLP byte containing the byte value pub(crate) fn is_short(&self) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.is_short(), @@ -603,7 +603,7 @@ impl RLPItemGadget { // Single RLP byte containing the length of the value pub(crate) fn is_long(&self) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.is_long(), @@ -615,7 +615,7 @@ impl RLPItemGadget { // RLP byte containing the lenght of the length, // followed by the length, followed by the actual data pub(crate) fn is_very_long(&self) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.is_very_long(), @@ -626,7 +626,7 @@ impl RLPItemGadget { /// Number of RLP bytes pub(crate) fn num_rlp_bytes(&self) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.num_rlp_bytes(), @@ -637,7 +637,7 @@ impl RLPItemGadget { /// Number of bytes in total (including RLP bytes) pub(crate) fn num_bytes(&self) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.num_bytes(), @@ -648,7 +648,7 @@ impl RLPItemGadget { /// Length of the value (excluding RLP bytes) pub(crate) fn len(&self) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.len(), @@ -673,7 +673,7 @@ impl RLPItemGadget { // Returns the RLC of the value if the RLP is a string, // returns the RLC of the full string if the RLP is a list. pub(crate) fn rlc_content(&self, r: &Expression) -> Expression { - let mut cb = MPTConstraintBuilder::::new(0, None); + let mut cb = MPTConstraintBuilder::::new(0, None, None); circuit!([meta, cb], { matchx! { self.value.is_string() => self.value.rlc_value(r), diff --git a/zkevm-circuits/src/mpt_circuit/start.rs b/zkevm-circuits/src/mpt_circuit/start.rs index d827094251..76fbe66073 100644 --- a/zkevm-circuits/src/mpt_circuit/start.rs +++ b/zkevm-circuits/src/mpt_circuit/start.rs @@ -83,7 +83,7 @@ impl StartConfig { pub fn assign>( &self, - region: &mut Region, + cached_region: &mut CachedRegion<'_, '_, F, S>, challenges: &S, mpt_config: &MPTConfig, pv: &mut MPTState, @@ -92,10 +92,6 @@ impl StartConfig { rlp_values: &[RLPItemWitness], ) -> Result<(), Error> { - let mut region = CachedRegion::new( - region, - challenges - ); let start = &node.start.clone().unwrap(); let _root_items = [ @@ -104,7 +100,7 @@ impl StartConfig { ]; self.proof_type - .assign(&mut region, offset, start.proof_type.scalar())?; + .assign(cached_region, offset, start.proof_type.scalar())?; let mut root = vec![0.scalar(); 2]; for is_s in [true, false] { @@ -113,7 +109,7 @@ impl StartConfig { } MainData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[main_memory()], start.proof_type as usize, @@ -125,7 +121,7 @@ impl StartConfig { for is_s in [true, false] { ParentData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[parent_memory(is_s)], root[is_s.idx()], @@ -134,7 +130,7 @@ impl StartConfig { root[is_s.idx()], )?; KeyData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[key_memory(is_s)], F::zero(), @@ -145,6 +141,8 @@ impl StartConfig { 0, )?; } + //println!("{} start ====> cahced_region.advice\n {:?}", offset, cached_region.advice); + //mpt_config.assign_static_lookups(cached_region, offset); Ok(()) } diff --git a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs index f54c400ae0..02cecbbd5e 100644 --- a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs @@ -259,7 +259,7 @@ impl StorageLeafConfig { pub fn assign>( &self, - region: &mut Region, + cached_region: &mut CachedRegion<'_, '_, F, S>, challenges: &S, mpt_config: &MPTConfig, pv: &mut MPTState, @@ -267,10 +267,6 @@ impl StorageLeafConfig { node: &Node, rlp_values: &[RLPItemWitness], ) -> Result<(), Error> { - let mut region = CachedRegion::new( - region, - challenges - ); let storage = &node.storage.clone().unwrap(); let key_items = [ @@ -286,7 +282,7 @@ impl StorageLeafConfig { let main_data = self.main_data - .witness_load(&mut region, offset, &pv.memory[main_memory()], 0)?; + .witness_load(cached_region, offset, &pv.memory[main_memory()], 0)?; let mut key_data = vec![KeyDataWitness::default(); 2]; let mut parent_data = vec![ParentDataWitness::default(); 2]; @@ -294,34 +290,34 @@ impl StorageLeafConfig { let mut value_rlc = vec![0.scalar(); 2]; for is_s in [true, false] { parent_data[is_s.idx()] = self.parent_data[is_s.idx()].witness_load( - &mut region, + cached_region, offset, &mut pv.memory[parent_memory(is_s)], 0, )?; let rlp_key_witness = self.rlp_key[is_s.idx()].assign( - &mut region, + cached_region, offset, &storage.list_rlp_bytes[is_s.idx()], &key_items[is_s.idx()], )?; self.is_not_hashed[is_s.idx()].assign( - &mut region, + cached_region, offset, rlp_key_witness.rlp_list.num_bytes().scalar(), 32.scalar(), )?; key_data[is_s.idx()] = self.key_data[is_s.idx()].witness_load( - &mut region, + cached_region, offset, &mut pv.memory[key_memory(is_s)], 0, )?; KeyData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[key_memory(is_s)], F::zero(), @@ -345,10 +341,10 @@ impl StorageLeafConfig { .iter() .zip(storage.value_rlp_bytes[is_s.idx()].iter()) { - cell.assign(&mut region, offset, byte.scalar())?; + cell.assign(cached_region, offset, byte.scalar())?; } let value_witness = self.rlp_value[is_s.idx()].assign( - &mut region, + cached_region, offset, &storage.value_rlp_bytes[is_s.idx()], )?; @@ -359,7 +355,7 @@ impl StorageLeafConfig { }; ParentData::witness_store( - &mut region, + cached_region, offset, &mut pv.memory[parent_memory(is_s)], F::zero(), @@ -369,7 +365,7 @@ impl StorageLeafConfig { )?; self.is_in_empty_trie[is_s.idx()].assign( - &mut region, + cached_region, offset, parent_data[is_s.idx()].rlc, pv.r, @@ -377,13 +373,13 @@ impl StorageLeafConfig { } let is_storage_mod_proof = self.is_storage_mod_proof.assign( - &mut region, + cached_region, offset, main_data.proof_type.scalar(), MPTProofType::StorageChanged.scalar(), )? == true.scalar(); let is_non_existing_proof = self.is_non_existing_storage_proof.assign( - &mut region, + cached_region, offset, main_data.proof_type.scalar(), MPTProofType::StorageDoesNotExist.scalar(), @@ -391,7 +387,7 @@ impl StorageLeafConfig { // Drifted leaf handling self.drifted.assign( - &mut region, + cached_region, offset, &parent_data, &storage.drifted_rlp_bytes, @@ -401,7 +397,7 @@ impl StorageLeafConfig { // Wrong leaf handling let key_rlc = self.wrong.assign( - &mut region, + cached_region, offset, is_non_existing_proof, &key_rlc, @@ -421,7 +417,7 @@ impl StorageLeafConfig { MPTProofType::Disabled }; mpt_config.mpt_table.assign_cached( - &mut region, + cached_region, offset, &MptUpdateRow { address_rlc: Value::known(main_data.address_rlc), @@ -433,6 +429,8 @@ impl StorageLeafConfig { root: Value::known(main_data.root), }, )?; + //println!("{} storage ====> cahced_region.advice\n {:?}", offset, cached_region.advice); + //mpt_config.assign_static_lookups(cached_region, offset); Ok(()) } From 439a3891c02c4e62d185d0a88ef11166bf3fe2fb Mon Sep 17 00:00:00 2001 From: Brecht Devos Date: Thu, 1 Jun 2023 15:47:09 +0200 Subject: [PATCH 064/102] Sync MPT to main (#1444) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Description This PR simply merges the current `main` into the MPT branch `mpt2`. This is the first step to get some further MPT changes merged into the MPT branch without making the PRs too big. ``` This PR contains: - Merge `main` into `mpt2` with the necessary changes to the MPT circuit ``` ### Issue Link [_link issue here_] ### Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update ### Contents - [_item_] ### Rationale [_design decisions and extended information_] ### How Has This Been Tested? Intermediate step, so limited testing --------- Signed-off-by: smtmfft Signed-off-by: smtmfft Co-authored-by: pinkiebell <40266861+pinkiebell@users.noreply.github.com> Co-authored-by: Haichen Shen Co-authored-by: z2trillion Co-authored-by: Eduard S Co-authored-by: adria0.eth <5526331+adria0@users.noreply.github.com> Co-authored-by: Han Co-authored-by: smtmfft <99081233+smtmfft@users.noreply.github.com> Co-authored-by: smtmfft Co-authored-by: Chih Cheng Liang Co-authored-by: DreamWuGit Co-authored-by: Rohit Narurkar Co-authored-by: Zhang Zhuo Co-authored-by: Ming Co-authored-by: Wu Sung Ming Co-authored-by: xiaodino Co-authored-by: Mason Liang Co-authored-by: Steven Co-authored-by: Carlos Pérez <37264926+CPerezz@users.noreply.github.com> Co-authored-by: Paul <108982045+ChengYueJia@users.noreply.github.com> Co-authored-by: AronisAt79 <45406504+AronisAt79@users.noreply.github.com> Co-authored-by: Mason Liang Co-authored-by: JohnWick2ETH <104916412+JohnWick2ETH@users.noreply.github.com> Co-authored-by: kunxian xia Co-authored-by: Leo Lara Co-authored-by: zengzengzenghuy <85567868+zengzengzenghuy@users.noreply.github.com> Co-authored-by: john xu Co-authored-by: Miha Stopar Co-authored-by: aguzmant103 <67167307+aguzmant103@users.noreply.github.com> Co-authored-by: Richord Co-authored-by: Kimi Wu Co-authored-by: Mickey Co-authored-by: Luozhu <70309026+LuozhuZhang@users.noreply.github.com> Co-authored-by: DoHoon Kim <59155248+DoHoonKim8@users.noreply.github.com> Co-authored-by: jeong0982 Co-authored-by: Andy Arditi Co-authored-by: David Nevado Co-authored-by: omahs <73983677+omahs@users.noreply.github.com> Co-authored-by: Richord Co-authored-by: ntampakas Co-authored-by: ashWhiteHat Co-authored-by: naure Co-authored-by: Aurélien Nicolas Co-authored-by: testuser-at-490752553772 Co-authored-by: xiaodino Co-authored-by: Thomas Pan <43927782+thomaspanf@users.noreply.github.com> Co-authored-by: Akase Cho Co-authored-by: Vu Co-authored-by: Alex Beregszaszi Co-authored-by: Enrico Bottazzi <85900164+enricobottazzi@users.noreply.github.com> Co-authored-by: adria0 --- .github/ISSUE_TEMPLATE/bug_form_template.yml | 23 + .github/ISSUE_TEMPLATE/config.yml | 1 + .../ISSUE_TEMPLATE/feature_form_template.yml | 18 + .../reporting_main.py | 35 + .../reporting_modules.py | 194 ++ .github/proverCiScripts/execBench.sh | 14 + .github/proverCiScripts/getSysstat.sh | 17 - .github/proverCiScripts/processResults.sh | 42 + .github/proverCiScripts/sadf.sh | 14 + .github/pull_request_template.md | 57 + .github/release-drafter.yml | 29 - .github/workflows/ci.yml | 55 +- .github/workflows/draft.yml | 16 - .../workflows/gh-actions-prover-benches.yml | 10 +- .github/workflows/github-ops.yml | 27 + .github/workflows/integration.yml | 72 +- .github/workflows/lints.yml | 18 +- .github/workflows/select-runner.yml | 45 - .github/workflows/test-features.yml | 82 + .gitignore | 1 + CODEOWNERS | 18 - CONTRIBUTING.md | 96 +- Cargo.lock | 1735 ++++++++++----- Cargo.toml | 4 +- Makefile | 44 +- README.md | 10 + bus-mapping/Cargo.toml | 4 +- bus-mapping/README.md | 2 +- bus-mapping/src/circuit_input_builder.rs | 375 +++- .../src/circuit_input_builder/access.rs | 207 +- .../src/circuit_input_builder/block.rs | 59 +- bus-mapping/src/circuit_input_builder/call.rs | 31 +- .../src/circuit_input_builder/execution.rs | 140 +- .../circuit_input_builder/input_state_ref.rs | 530 ++++- .../src/circuit_input_builder/tracer_tests.rs | 535 +++-- .../src/circuit_input_builder/transaction.rs | 66 +- bus-mapping/src/error.rs | 85 +- bus-mapping/src/evm.rs | 3 +- bus-mapping/src/evm/opcodes.rs | 521 ++--- bus-mapping/src/evm/opcodes/address.rs | 13 +- bus-mapping/src/evm/opcodes/balance.rs | 265 ++- bus-mapping/src/evm/opcodes/begin_end_tx.rs | 327 +++ bus-mapping/src/evm/opcodes/calldatacopy.rs | 180 +- bus-mapping/src/evm/opcodes/calldataload.rs | 162 +- bus-mapping/src/evm/opcodes/caller.rs | 13 +- bus-mapping/src/evm/opcodes/callop.rs | 618 +++++- bus-mapping/src/evm/opcodes/callvalue.rs | 8 +- bus-mapping/src/evm/opcodes/chainid.rs | 13 +- bus-mapping/src/evm/opcodes/codecopy.rs | 82 +- bus-mapping/src/evm/opcodes/create.rs | 99 +- bus-mapping/src/evm/opcodes/dup.rs | 11 +- .../src/evm/opcodes/error_invalid_jump.rs | 48 + bus-mapping/src/evm/opcodes/error_oog_call.rs | 96 + bus-mapping/src/evm/opcodes/error_oog_exp.rs | 36 + bus-mapping/src/evm/opcodes/error_oog_log.rs | 50 + .../src/evm/opcodes/error_oog_memory_copy.rs | 73 + .../src/evm/opcodes/error_oog_sload_sstore.rs | 95 + .../opcodes/error_return_data_outofbound.rs | 146 ++ bus-mapping/src/evm/opcodes/error_simple.rs | 28 + .../src/evm/opcodes/error_write_protection.rs | 69 + bus-mapping/src/evm/opcodes/exp.rs | 103 + bus-mapping/src/evm/opcodes/extcodecopy.rs | 486 ++++- bus-mapping/src/evm/opcodes/extcodehash.rs | 97 +- bus-mapping/src/evm/opcodes/extcodesize.rs | 247 ++- bus-mapping/src/evm/opcodes/gasprice.rs | 8 +- bus-mapping/src/evm/opcodes/logs.rs | 20 +- .../src/evm/opcodes/memory_expansion_test.rs | 21 +- bus-mapping/src/evm/opcodes/mload.rs | 12 +- bus-mapping/src/evm/opcodes/mstore.rs | 9 +- bus-mapping/src/evm/opcodes/origin.rs | 8 +- bus-mapping/src/evm/opcodes/return.rs | 213 -- bus-mapping/src/evm/opcodes/return_revert.rs | 345 +++ bus-mapping/src/evm/opcodes/returndatacopy.rs | 268 ++- bus-mapping/src/evm/opcodes/returndatasize.rs | 144 ++ bus-mapping/src/evm/opcodes/selfbalance.rs | 13 +- bus-mapping/src/evm/opcodes/sha3.rs | 210 +- bus-mapping/src/evm/opcodes/sload.rs | 6 +- bus-mapping/src/evm/opcodes/sstore.rs | 29 +- bus-mapping/src/evm/opcodes/stackonlyop.rs | 289 ++- bus-mapping/src/evm/opcodes/stop.rs | 55 +- bus-mapping/src/evm/opcodes/swap.rs | 12 +- bus-mapping/src/exec_trace.rs | 2 +- bus-mapping/src/lib.rs | 15 +- bus-mapping/src/mock.rs | 51 +- bus-mapping/src/operation.rs | 132 +- bus-mapping/src/operation/container.rs | 30 +- bus-mapping/src/precompile.rs | 23 + bus-mapping/src/state_db.rs | 73 +- circuit-benchmarks/.gitignore | 1 - circuit-benchmarks/Cargo.toml | 6 +- circuit-benchmarks/build.rs | 22 - circuit-benchmarks/src/bit_keccak.rs | 100 - circuit-benchmarks/src/bytecode_circuit.rs | 47 +- circuit-benchmarks/src/constants.rs | 5 + circuit-benchmarks/src/copy_circuit.rs | 161 ++ circuit-benchmarks/src/evm_circuit.rs | 108 +- circuit-benchmarks/src/exp_circuit.rs | 153 ++ circuit-benchmarks/src/lib.rs | 18 +- circuit-benchmarks/src/packed_multi_keccak.rs | 46 +- .../src/{packed_keccak.rs => pi_circuit.rs} | 82 +- circuit-benchmarks/src/state_circuit.rs | 36 +- circuit-benchmarks/src/super_circuit.rs | 55 +- circuit-benchmarks/src/tx_circuit.rs | 64 +- eth-types/Cargo.toml | 6 +- eth-types/src/bytecode.rs | 233 +- eth-types/src/evm_types.rs | 39 +- eth-types/src/evm_types/gas_utils.rs | 10 +- eth-types/src/evm_types/memory.rs | 50 +- eth-types/src/evm_types/opcode_ids.rs | 188 +- eth-types/src/evm_types/stack.rs | 17 +- eth-types/src/evm_types/storage.rs | 9 +- eth-types/src/geth_types.rs | 110 +- eth-types/src/lib.rs | 128 +- eth-types/src/macros.rs | 20 + eth-types/src/sign_types.rs | 14 +- gadgets/Cargo.toml | 2 +- gadgets/src/batched_is_zero.rs | 256 +++ gadgets/src/binary_number.rs | 24 +- gadgets/src/evm_word.rs | 278 --- gadgets/src/is_zero.rs | 58 +- gadgets/src/less_than.rs | 69 +- gadgets/src/lib.rs | 23 +- gadgets/src/monotone.rs | 307 --- gadgets/src/mul_add.rs | 504 +++++ gadgets/src/util.rs | 94 +- geth-utils/Cargo.toml | 2 + geth-utils/README.md | 2 +- geth-utils/build.rs | 6 +- geth-utils/gethutil/trace.go | 36 +- geth-utils/go.mod | 2 +- geth-utils/go.sum | 855 +++++++- geth-utils/src/lib.rs | 6 +- integration-tests/Cargo.toml | 12 +- integration-tests/README.md | 6 +- integration-tests/docker-compose.yml | 2 +- integration-tests/run.sh | 10 +- .../src/bin/gen_blockchain_data.rs | 27 +- .../src/integration_test_circuits.rs | 339 +++ integration-tests/src/lib.rs | 18 +- .../tests/circuit_input_builder.rs | 36 +- integration-tests/tests/circuits.rs | 238 +- integration-tests/tests/rpc.rs | 3 +- keccak256/Cargo.toml | 2 + keccak256/src/arith_helpers.rs | 5 +- keccak256/src/keccak_arith.rs | 16 +- keccak256/src/lib.rs | 12 - keccak256/src/plain.rs | 57 +- mock/src/account.rs | 8 +- mock/src/block.rs | 11 +- mock/src/lib.rs | 97 +- mock/src/test_ctx.rs | 23 +- mock/src/transaction.rs | 32 +- rust-toolchain | 2 +- rustfmt.toml | 10 +- testool/Cargo.toml | 8 +- testool/Config.toml | 345 ++- testool/README.md | 114 + testool/codehash.txt | 1938 ++++++++--------- testool/debug.sh | 1 - testool/docker/solc/Dockerfile | 2 +- testool/loop.sh | 4 - testool/pre_commit.sh | 5 - testool/raw.sh | 2 - testool/src/abi.rs | 3 +- testool/src/compiler.rs | 222 +- testool/src/config.rs | 108 +- testool/src/main.rs | 263 +-- testool/src/statetest/executor.rs | 649 ++---- testool/src/statetest/json.rs | 249 +-- testool/src/statetest/mod.rs | 7 +- testool/src/statetest/parse.rs | 164 ++ testool/src/statetest/report.handlebars | 44 +- testool/src/statetest/results.rs | 199 +- testool/src/statetest/spec.rs | 286 +++ testool/src/statetest/suite.rs | 157 +- testool/src/statetest/yaml.rs | 257 +-- testool/src/utils.rs | 61 +- testool/test.sh | 2 - zkevm-circuits/Cargo.toml | 29 +- zkevm-circuits/src/bin/stats/helpers.rs | 243 +++ zkevm-circuits/src/bin/stats/main.rs | 185 ++ zkevm-circuits/src/bytecode_circuit.rs | 12 +- .../src/bytecode_circuit/bytecode_unroller.rs | 907 +------- .../src/bytecode_circuit/circuit.rs | 870 ++++++++ zkevm-circuits/src/bytecode_circuit/dev.rs | 103 +- zkevm-circuits/src/bytecode_circuit/test.rs | 325 +++ .../src/circuit_tools/constraint_builder.rs | 16 +- zkevm-circuits/src/circuit_tools/gadgets.rs | 12 +- zkevm-circuits/src/copy_circuit.rs | 924 ++++---- zkevm-circuits/src/copy_circuit/dev.rs | 77 + zkevm-circuits/src/copy_circuit/test.rs | 352 +++ zkevm-circuits/src/copy_circuit/util.rs | 22 + zkevm-circuits/src/evm_circuit.rs | 691 +++--- zkevm-circuits/src/evm_circuit/execution.rs | 974 ++++++--- .../src/evm_circuit/execution/add_sub.rs | 36 +- .../src/evm_circuit/execution/addmod.rs | 114 +- .../src/evm_circuit/execution/address.rs | 54 +- .../src/evm_circuit/execution/balance.rs | 302 +++ .../src/evm_circuit/execution/begin_tx.rs | 735 +++++-- .../src/evm_circuit/execution/bitwise.rs | 30 +- .../src/evm_circuit/execution/block_ctx.rs | 34 +- .../src/evm_circuit/execution/blockhash.rs | 140 +- .../src/evm_circuit/execution/byte.rs | 28 +- .../src/evm_circuit/execution/calldatacopy.rs | 175 +- .../src/evm_circuit/execution/calldataload.rs | 326 +-- .../src/evm_circuit/execution/calldatasize.rs | 149 +- .../src/evm_circuit/execution/caller.rs | 21 +- .../src/evm_circuit/execution/callop.rs | 1072 +++++---- .../src/evm_circuit/execution/callvalue.rs | 37 +- .../src/evm_circuit/execution/chainid.rs | 38 +- .../src/evm_circuit/execution/codecopy.rs | 123 +- .../src/evm_circuit/execution/codesize.rs | 32 +- .../src/evm_circuit/execution/comparator.rs | 36 +- .../src/evm_circuit/execution/dummy.rs | 29 +- .../src/evm_circuit/execution/dup.rs | 41 +- .../src/evm_circuit/execution/end_block.rs | 174 +- .../src/evm_circuit/execution/end_tx.rs | 60 +- .../execution/error_invalid_jump.rs | 427 ++++ .../execution/error_invalid_opcode.rs | 150 ++ .../evm_circuit/execution/error_oog_call.rs | 388 ++++ .../execution/error_oog_constant.rs | 213 +- .../evm_circuit/execution/error_oog_exp.rs | 234 ++ .../evm_circuit/execution/error_oog_log.rs | 313 +++ .../execution/error_oog_memory_copy.rs | 406 ++++ .../execution/error_oog_sload_sstore.rs | 527 +++++ .../execution/error_oog_static_memory.rs | 19 +- .../execution/error_return_data_oo_bound.rs | 295 +++ .../src/evm_circuit/execution/error_stack.rs | 243 +++ .../execution/error_write_protection.rs | 303 +++ .../src/evm_circuit/execution/exp.rs | 315 +++ .../src/evm_circuit/execution/extcodecopy.rs | 454 ++++ .../src/evm_circuit/execution/extcodehash.rs | 147 +- .../src/evm_circuit/execution/extcodesize.rs | 236 ++ .../src/evm_circuit/execution/gas.rs | 68 +- .../src/evm_circuit/execution/gasprice.rs | 26 +- .../src/evm_circuit/execution/is_zero.rs | 33 +- .../src/evm_circuit/execution/jump.rs | 37 +- .../src/evm_circuit/execution/jumpdest.rs | 17 +- .../src/evm_circuit/execution/jumpi.rs | 124 +- .../src/evm_circuit/execution/logs.rs | 179 +- .../src/evm_circuit/execution/memory.rs | 53 +- .../src/evm_circuit/execution/msize.rs | 29 +- .../src/evm_circuit/execution/mul_div_mod.rs | 36 +- .../src/evm_circuit/execution/mulmod.rs | 118 +- .../src/evm_circuit/execution/not.rs | 27 +- .../src/evm_circuit/execution/origin.rs | 21 +- .../src/evm_circuit/execution/pc.rs | 24 +- .../src/evm_circuit/execution/pop.rs | 54 +- .../src/evm_circuit/execution/push.rs | 66 +- .../execution/{return.rs => return_revert.rs} | 410 ++-- .../evm_circuit/execution/returndatacopy.rs | 372 ++++ .../evm_circuit/execution/returndatasize.rs | 158 ++ .../src/evm_circuit/execution/sar.rs | 471 ++++ .../src/evm_circuit/execution/sdiv_smod.rs | 29 +- .../src/evm_circuit/execution/selfbalance.rs | 45 +- .../src/evm_circuit/execution/sha3.rs | 106 +- .../src/evm_circuit/execution/shl_shr.rs | 67 +- .../execution/signed_comparator.rs | 39 +- .../src/evm_circuit/execution/signextend.rs | 38 +- .../src/evm_circuit/execution/sload.rs | 126 +- .../src/evm_circuit/execution/sstore.rs | 364 +--- .../src/evm_circuit/execution/stop.rs | 150 +- .../src/evm_circuit/execution/swap.rs | 57 +- zkevm-circuits/src/evm_circuit/param.rs | 86 +- zkevm-circuits/src/evm_circuit/step.rs | 362 ++- zkevm-circuits/src/evm_circuit/table.rs | 102 +- zkevm-circuits/src/evm_circuit/test.rs | 36 + zkevm-circuits/src/evm_circuit/util.rs | 369 +++- .../src/evm_circuit/util/common_gadget.rs | 817 ++++++- .../evm_circuit/util/constraint_builder.rs | 532 +++-- .../src/evm_circuit/util/instrumentation.rs | 164 ++ .../src/evm_circuit/util/math_gadget.rs | 1359 +----------- .../evm_circuit/util/math_gadget/abs_word.rs | 193 ++ .../evm_circuit/util/math_gadget/add_words.rs | 300 +++ .../util/math_gadget/batched_is_zero.rs | 187 ++ .../util/math_gadget/binary_number.rs | 68 + .../evm_circuit/util/math_gadget/byte_size.rs | 196 ++ .../evm_circuit/util/math_gadget/cmp_words.rs | 221 ++ .../util/math_gadget/comparison.rs | 196 ++ .../util/math_gadget/constant_division.rs | 217 ++ .../evm_circuit/util/math_gadget/is_equal.rs | 142 ++ .../evm_circuit/util/math_gadget/is_zero.rs | 128 ++ .../src/evm_circuit/util/math_gadget/lt.rs | 178 ++ .../evm_circuit/util/math_gadget/lt_word.rs | 158 ++ .../evm_circuit/util/math_gadget/min_max.rs | 206 ++ .../evm_circuit/util/math_gadget/modulo.rs | 242 ++ .../util/math_gadget/mul_add_words.rs | 388 ++++ .../util/math_gadget/mul_add_words512.rs | 360 +++ .../util/math_gadget/mul_word_u64.rs | 203 ++ .../util/math_gadget/pair_select.rs | 187 ++ .../util/math_gadget/range_check.rs | 109 + .../src/evm_circuit/util/math_gadget/rlp.rs | 531 +++++ .../evm_circuit/util/math_gadget/test_util.rs | 276 +++ .../src/evm_circuit/util/memory_gadget.rs | 41 +- zkevm-circuits/src/exp_circuit.rs | 548 +++++ zkevm-circuits/src/exp_circuit/dev.rs | 37 + zkevm-circuits/src/exp_circuit/param.rs | 10 + zkevm-circuits/src/exp_circuit/test.rs | 152 ++ zkevm-circuits/src/keccak_circuit.rs | 1056 ++++++++- .../src/keccak_circuit/cell_manager.rs | 207 ++ zkevm-circuits/src/keccak_circuit/dev.rs | 48 + .../src/keccak_circuit/keccak_bit.rs | 1024 --------- .../src/keccak_circuit/keccak_packed.rs | 1712 --------------- .../src/keccak_circuit/keccak_packed_multi.rs | 1504 ++----------- zkevm-circuits/src/keccak_circuit/param.rs | 66 + zkevm-circuits/src/keccak_circuit/table.rs | 296 +++ zkevm-circuits/src/keccak_circuit/test.rs | 145 ++ zkevm-circuits/src/keccak_circuit/util.rs | 493 ++--- zkevm-circuits/src/lib.rs | 5 +- zkevm-circuits/src/mpt_circuit.rs | 121 +- .../src/mpt_circuit/account_leaf.rs | 145 +- zkevm-circuits/src/mpt_circuit/branch.rs | 20 +- zkevm-circuits/src/mpt_circuit/extension.rs | 22 +- .../src/mpt_circuit/extension_branch.rs | 2 +- zkevm-circuits/src/mpt_circuit/helpers.rs | 60 +- zkevm-circuits/src/mpt_circuit/rlp_gadgets.rs | 50 +- zkevm-circuits/src/mpt_circuit/start.rs | 34 +- .../src/mpt_circuit/storage_leaf.rs | 88 +- zkevm-circuits/src/mpt_circuit/witness_row.rs | 55 +- zkevm-circuits/src/pi_circuit.rs | 989 +++++++-- zkevm-circuits/src/pi_circuit/dev.rs | 57 + zkevm-circuits/src/pi_circuit/param.rs | 5 + zkevm-circuits/src/pi_circuit/test.rs | 132 ++ zkevm-circuits/src/root_circuit.rs | 150 ++ .../src/root_circuit/aggregation.rs | 747 +++++++ zkevm-circuits/src/root_circuit/test.rs | 77 + zkevm-circuits/src/state_circuit.rs | 533 ++--- .../src/state_circuit/constraint_builder.rs | 235 +- zkevm-circuits/src/state_circuit/dev.rs | 120 + .../state_circuit/lexicographic_ordering.rs | 30 +- zkevm-circuits/src/state_circuit/lookups.rs | 11 +- .../multiple_precision_integer.rs | 27 +- zkevm-circuits/src/state_circuit/param.rs | 3 + .../random_linear_combination.rs | 18 +- zkevm-circuits/src/state_circuit/test.rs | 238 +- zkevm-circuits/src/super_circuit.rs | 703 +++--- zkevm-circuits/src/super_circuit/test.rs | 174 ++ zkevm-circuits/src/table.rs | 1138 +--------- zkevm-circuits/src/table/block_table.rs | 100 + zkevm-circuits/src/table/bytecode_table.rs | 105 + zkevm-circuits/src/table/copy_table.rs | 287 +++ zkevm-circuits/src/table/exp_table.rs | 207 ++ zkevm-circuits/src/table/keccak_table.rs | 158 ++ zkevm-circuits/src/table/mpt_table.rs | 162 ++ zkevm-circuits/src/table/rw_table.rs | 135 ++ zkevm-circuits/src/table/tx_table.rs | 217 ++ zkevm-circuits/src/test_util.rs | 312 ++- zkevm-circuits/src/tx_circuit.rs | 339 ++- zkevm-circuits/src/tx_circuit/dev.rs | 63 + zkevm-circuits/src/tx_circuit/sign_verify.rs | 149 +- zkevm-circuits/src/tx_circuit/test.rs | 116 + zkevm-circuits/src/util.rs | 181 +- zkevm-circuits/src/util/cell_manager.rs | 8 + zkevm-circuits/src/witness.rs | 6 +- zkevm-circuits/src/witness/block.rs | 232 +- zkevm-circuits/src/witness/bytecode.rs | 37 +- zkevm-circuits/src/witness/call.rs | 42 - zkevm-circuits/src/witness/mpt.rs | 165 +- zkevm-circuits/src/witness/rw.rs | 292 ++- zkevm-circuits/src/witness/step.rs | 239 -- zkevm-circuits/src/witness/tx.rs | 213 +- zkevm-circuits/tests/prover_error.rs | 111 + 362 files changed, 42883 insertions(+), 21272 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_form_template.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_form_template.yml create mode 100644 .github/proverCiScripts/benchmarks_result_reporting/reporting_main.py create mode 100644 .github/proverCiScripts/benchmarks_result_reporting/reporting_modules.py create mode 100755 .github/proverCiScripts/processResults.sh create mode 100755 .github/proverCiScripts/sadf.sh create mode 100644 .github/pull_request_template.md delete mode 100644 .github/release-drafter.yml delete mode 100644 .github/workflows/draft.yml create mode 100644 .github/workflows/github-ops.yml delete mode 100644 .github/workflows/select-runner.yml create mode 100644 .github/workflows/test-features.yml delete mode 100644 CODEOWNERS create mode 100644 bus-mapping/src/evm/opcodes/begin_end_tx.rs create mode 100644 bus-mapping/src/evm/opcodes/error_invalid_jump.rs create mode 100644 bus-mapping/src/evm/opcodes/error_oog_call.rs create mode 100644 bus-mapping/src/evm/opcodes/error_oog_exp.rs create mode 100644 bus-mapping/src/evm/opcodes/error_oog_log.rs create mode 100644 bus-mapping/src/evm/opcodes/error_oog_memory_copy.rs create mode 100644 bus-mapping/src/evm/opcodes/error_oog_sload_sstore.rs create mode 100644 bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs create mode 100644 bus-mapping/src/evm/opcodes/error_simple.rs create mode 100644 bus-mapping/src/evm/opcodes/error_write_protection.rs create mode 100644 bus-mapping/src/evm/opcodes/exp.rs delete mode 100644 bus-mapping/src/evm/opcodes/return.rs create mode 100644 bus-mapping/src/evm/opcodes/return_revert.rs create mode 100644 bus-mapping/src/evm/opcodes/returndatasize.rs create mode 100644 bus-mapping/src/precompile.rs delete mode 100644 circuit-benchmarks/.gitignore delete mode 100644 circuit-benchmarks/build.rs delete mode 100644 circuit-benchmarks/src/bit_keccak.rs create mode 100644 circuit-benchmarks/src/constants.rs create mode 100644 circuit-benchmarks/src/copy_circuit.rs create mode 100644 circuit-benchmarks/src/exp_circuit.rs rename circuit-benchmarks/src/{packed_keccak.rs => pi_circuit.rs} (52%) create mode 100644 gadgets/src/batched_is_zero.rs delete mode 100644 gadgets/src/evm_word.rs delete mode 100644 gadgets/src/monotone.rs create mode 100644 gadgets/src/mul_add.rs create mode 100644 integration-tests/src/integration_test_circuits.rs create mode 100644 testool/README.md delete mode 100755 testool/debug.sh delete mode 100755 testool/loop.sh delete mode 100755 testool/pre_commit.sh delete mode 100755 testool/raw.sh create mode 100644 testool/src/statetest/parse.rs create mode 100644 testool/src/statetest/spec.rs delete mode 100755 testool/test.sh create mode 100644 zkevm-circuits/src/bin/stats/helpers.rs create mode 100644 zkevm-circuits/src/bin/stats/main.rs create mode 100644 zkevm-circuits/src/bytecode_circuit/circuit.rs create mode 100644 zkevm-circuits/src/bytecode_circuit/test.rs create mode 100644 zkevm-circuits/src/copy_circuit/dev.rs create mode 100644 zkevm-circuits/src/copy_circuit/test.rs create mode 100644 zkevm-circuits/src/copy_circuit/util.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/balance.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_invalid_jump.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_invalid_opcode.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_oog_exp.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_oog_log.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_oog_memory_copy.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_oog_sload_sstore.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_return_data_oo_bound.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_stack.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/error_write_protection.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/exp.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/extcodecopy.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/extcodesize.rs rename zkevm-circuits/src/evm_circuit/execution/{return.rs => return_revert.rs} (55%) create mode 100644 zkevm-circuits/src/evm_circuit/execution/returndatacopy.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/returndatasize.rs create mode 100644 zkevm-circuits/src/evm_circuit/execution/sar.rs create mode 100644 zkevm-circuits/src/evm_circuit/test.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/instrumentation.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/abs_word.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/add_words.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/batched_is_zero.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/binary_number.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/byte_size.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/cmp_words.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/comparison.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/constant_division.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/is_equal.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/is_zero.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/lt.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/lt_word.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/min_max.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/modulo.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/mul_add_words512.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/mul_word_u64.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/pair_select.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/range_check.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/rlp.rs create mode 100644 zkevm-circuits/src/evm_circuit/util/math_gadget/test_util.rs create mode 100644 zkevm-circuits/src/exp_circuit.rs create mode 100644 zkevm-circuits/src/exp_circuit/dev.rs create mode 100644 zkevm-circuits/src/exp_circuit/param.rs create mode 100644 zkevm-circuits/src/exp_circuit/test.rs create mode 100644 zkevm-circuits/src/keccak_circuit/cell_manager.rs create mode 100644 zkevm-circuits/src/keccak_circuit/dev.rs delete mode 100644 zkevm-circuits/src/keccak_circuit/keccak_bit.rs delete mode 100644 zkevm-circuits/src/keccak_circuit/keccak_packed.rs create mode 100644 zkevm-circuits/src/keccak_circuit/param.rs create mode 100644 zkevm-circuits/src/keccak_circuit/table.rs create mode 100644 zkevm-circuits/src/keccak_circuit/test.rs create mode 100644 zkevm-circuits/src/pi_circuit/dev.rs create mode 100644 zkevm-circuits/src/pi_circuit/param.rs create mode 100644 zkevm-circuits/src/pi_circuit/test.rs create mode 100644 zkevm-circuits/src/root_circuit.rs create mode 100644 zkevm-circuits/src/root_circuit/aggregation.rs create mode 100644 zkevm-circuits/src/root_circuit/test.rs create mode 100644 zkevm-circuits/src/state_circuit/dev.rs create mode 100644 zkevm-circuits/src/state_circuit/param.rs create mode 100644 zkevm-circuits/src/super_circuit/test.rs create mode 100644 zkevm-circuits/src/table/block_table.rs create mode 100644 zkevm-circuits/src/table/bytecode_table.rs create mode 100644 zkevm-circuits/src/table/copy_table.rs create mode 100644 zkevm-circuits/src/table/exp_table.rs create mode 100644 zkevm-circuits/src/table/keccak_table.rs create mode 100644 zkevm-circuits/src/table/mpt_table.rs create mode 100644 zkevm-circuits/src/table/rw_table.rs create mode 100644 zkevm-circuits/src/table/tx_table.rs create mode 100644 zkevm-circuits/src/tx_circuit/dev.rs create mode 100644 zkevm-circuits/src/tx_circuit/test.rs create mode 100644 zkevm-circuits/src/util/cell_manager.rs delete mode 100644 zkevm-circuits/src/witness/call.rs delete mode 100644 zkevm-circuits/src/witness/step.rs create mode 100644 zkevm-circuits/tests/prover_error.rs diff --git a/.github/ISSUE_TEMPLATE/bug_form_template.yml b/.github/ISSUE_TEMPLATE/bug_form_template.yml new file mode 100644 index 0000000000..be52078ee6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_form_template.yml @@ -0,0 +1,23 @@ +name: Bug report +description: File a bug report +labels: ["T-bug"] +body: + - type: markdown + attributes: + value: | + Please ensure that the bug has not already been filed in the issue tracker. + - type: input + attributes: + label: What command(s) is the bug in? + description: Leave empty if not relevant + placeholder: "For example: make test" + - type: textarea + attributes: + label: Describe the bug + description: Please include relevant code snippets as well if relevant. + validations: + required: true + - type: textarea + attributes: + label: Concrete steps to reproduce the bug. If it's able reproduce via testool, please share `test_id` from jenkins report + description: Leave empty if not relevant diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..0086358db1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: true diff --git a/.github/ISSUE_TEMPLATE/feature_form_template.yml b/.github/ISSUE_TEMPLATE/feature_form_template.yml new file mode 100644 index 0000000000..7d202a0a6c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_form_template.yml @@ -0,0 +1,18 @@ +name: Feature request +description: Suggest a feature +labels: ["T-feature"] +body: + - type: markdown + attributes: + value: | + Please ensure that the feature has not already been requested in the issue tracker. + - type: textarea + attributes: + label: Describe the feature you would like + description: Please also describe what the feature is aiming to solve, if relevant. + validations: + required: true + - type: textarea + attributes: + label: Additional context + description: Add any other context to the feature (like screenshots, resources) diff --git a/.github/proverCiScripts/benchmarks_result_reporting/reporting_main.py b/.github/proverCiScripts/benchmarks_result_reporting/reporting_main.py new file mode 100644 index 0000000000..b3a3ec91f3 --- /dev/null +++ b/.github/proverCiScripts/benchmarks_result_reporting/reporting_main.py @@ -0,0 +1,35 @@ +import argparse, json +from pprint import pprint +import reporting_modules as rmod + +env = json.load(open('/home/ubuntu/env.json')) +cstats = '/home/ubuntu/cpu.stats' +mstats = '/home/ubuntu/mem.stats' + +def main(): + parser = argparse.ArgumentParser( + prog = 'BenchmarkResults', + usage = 'python3 reporting_main.py 13 EVM 19', + description = 'Writes circuit benchmark results to postgresql, uploads logfiles to s3 bucket', + ) + parser.add_argument('pr') + parser.add_argument('circuit') + parser.add_argument('degree') + parser.add_argument('test_id') + args = parser.parse_args() + pr, circuit, degree, test_id = (args.pr, args.circuit, args.degree, args.test_id) + test_result = rmod.log_processor(pr,circuit, degree) + cpustats, memstats, sysstat = rmod.calc_stats(cstats,mstats) + data = rmod.prepare_result_dataframe(test_result, sysstat, env, test_id) + table = 'testresults_circuitbenchmark' + engine = rmod.pgsql_engine(env['db']) + data.to_sql(table,engine,if_exists='append') + ms = rmod.write_mem_time(engine,memstats, test_id) + cs = rmod.write_cpuall_time(engine,cpustats, test_id) + + url = f'{env["grafana_dashboard_prefix"]}{test_id}'.replace(" ", "") + print(f'Test Result: {url}') + +if __name__ == '__main__': + main() + diff --git a/.github/proverCiScripts/benchmarks_result_reporting/reporting_modules.py b/.github/proverCiScripts/benchmarks_result_reporting/reporting_modules.py new file mode 100644 index 0000000000..476c877888 --- /dev/null +++ b/.github/proverCiScripts/benchmarks_result_reporting/reporting_modules.py @@ -0,0 +1,194 @@ +import pandas as pd, json, datetime, itertools +from sqlalchemy import create_engine, text +import warnings, time, os + + +warnings.simplefilter(action='ignore', category=FutureWarning) +warnings.simplefilter(action='ignore', category=UserWarning) +pd.options.mode.chained_assignment = None + +def pgsql_engine(pgsqldb): + ''' + creates a psql engine instance + ''' + user = pgsqldb['user'] + password = pgsqldb['password'] + host = pgsqldb['host'] + database = pgsqldb['database'] + engine = create_engine(f'postgresql://{user}:{password}@{host}:5432/{database}') + + return engine + +def prepare_result_dataframe(test_result, sysstat,env, test_id): + ''' + prepares postgres data (in the form of dataframe) for table circuit_benchmarks + ''' + try: + r = { + 'pull_request' : test_result['pull_request'], + 'test_id' : test_id, + 'circuit' : test_result['circuit'], + 'degree' : test_result['degree'], + 'test_result' : test_result['result'], + 'test_date' : datetime.datetime.now().date(), + 'setup_gen' : test_result['setup_gen'], + 'proof_gen' : test_result['proof_gen'], + 'proof_ver' : test_result['proof_ver'], + 'max_ram' : sysstat['max_ram'], + 'cpu_all_Average' : sysstat['cpu_all_Average'], + 'cpu_all_Max' : sysstat['cpu_all_Max'], + 'cpu_count' : sysstat['cpu_count'], + 'sysstats_url' : f'{env["grafana_dashboard_prefix"]}{test_id}', + 'logsurl' : f'{env["s3endpoint"]}{test_id}.tar.gz' + } + + except Exception as e: + print(e) + + test_id = r['test_id'] + r = pd.DataFrame([r]) + r = r.set_index('test_date') + + return r + +def write_mem_time(engine, mem_statistics, test_id, dummy=False): + ''' + adds mem stats df as time series data to table mem_stats + ''' + table = 'testresults_cbmemtime' + mem_statistics['dummy'] = mem_statistics['timestamp'].apply(lambda x: f'{dummy}') + mem_statistics['test_id'] = mem_statistics['timestamp'].apply(lambda x: f'{test_id}') + mem_statistics.to_sql(table,engine,if_exists='append',index=False) + +def write_cpuall_time(engine, cpu_statistics, test_id, dummy=False): + ''' + adds cpu stats df as time series data to table mem_stats + ''' + table = 'testresults_cbcpualltime' + cpu_statistics['dummy'] = cpu_statistics['timestamp'].apply(lambda x: f'{dummy}') + cpu_statistics['test_id'] = cpu_statistics['timestamp'].apply(lambda x: f'{test_id}') + cpu_statistics.to_sql(table,engine,if_exists='append',index=False) + +def calc_stats(cstats,mstats): + ''' + returns 2 dataframes with cpu/mem stats to be consumed by postgresql engine + returns a dict with average/max cpu and max ram utilization durint the benchmark + ''' + dfcpu,cpus = load_stats(cstats) + cpustats,cpu_all_Max,cpu_all_Average = process_cpustats(dfcpu) + dfmem, _ = load_stats(mstats) + memstats,max_ram = process_memstats(dfmem) + sysstat = { + 'cpu_all_Average': cpu_all_Average, + 'cpu_all_Max' : cpu_all_Max, + 'cpu_count' : cpus, + 'max_ram' : f'{max_ram}Gb' + } + + return cpustats, memstats, sysstat + +def log_processor(pull_request,circuit, degree): + ''' + Exports test metadata and result metrics from prover logfile + ''' + SETUP_PREFIX = "[Setup generation]" + PROOFGEN_PREFIX = "[Proof generation]" + PROOFVER_PREFIX = "[Proof verification]" + logfile = [i for i in os.listdir('/home/ubuntu/') if 'proverlog' in i][0] + f = open(f'/home/ubuntu/{logfile}', 'r') + logdata = f.read() + logdata = logdata.split("\n") + running = [i for i in logdata if 'running' in i and 'test' in i][0].split()[1] + if running != '0': + r = [i.split(":")[1].split(".")[0].replace(" ","") for i in logdata if 'test result' in i][0] + if r == 'ok': + result = 'PASSED' + try: + sg = ''.join(g[0] for g in itertools.groupby([i for i in logdata if 'End' in i and SETUP_PREFIX in i ][0])).split('.', 1)[-1] + except: + sg = 'None' + try: + pg = ''.join(g[0] for g in itertools.groupby([i for i in logdata if 'End' in i and PROOFGEN_PREFIX in i ][0])).split('.', 1)[-1] + except: + pg = 'None' + try: + pv = ''.join(g[0] for g in itertools.groupby([i for i in logdata if 'End' in i and PROOFVER_PREFIX in i ][0])).split('.', 1)[-1] + except: + pv = 'None' + logdata = { + 'pull_request': pull_request, + 'circuit' : circuit, + 'degree' : degree, + 'result' : result, + 'setup_gen' : sg, + 'proof_gen' : pg, + 'proof_ver' : pv + } + else: + result = 'FAILED' + logdata = { + 'pull_request': pull_request, + 'circuit' : circuit, + 'degree' : degree, + 'result' : result, + 'setup_gen' : 'None', + 'proof_gen' : 'None', + 'proof_ver' : 'None' + } + + else: + result = 'None' + logdata = { + 'pull_request': pull_request, + 'circuit' : circuit, + 'degree' : degree, + 'result' : result, + 'setup_gen' : 'NoTestExecuted', + 'proof_gen' : 'NoTestExecuted', + 'proof_ver' : 'NoTestExecuted' + } + + + return logdata + +def load_stats(file): + ''' + loads raw mem/cpu sar data from csv to dataframe + ''' + try: + with open(file,'r') as filedata: + filedatalist = [i for i in filedata.read().splitlines()] + header = [i for i in filedatalist if 'LINUX-RESTART' in i][0] + cpus = header.split('(')[1].split()[0] + cpudatalist = [i for i in filedatalist if 'LINUX-RESTART' not in i] + columns = cpudatalist[0].split(';') + cpudatalist = [i for i in cpudatalist if 'hostname' not in i] + df = pd.DataFrame([i.split(';') for i in cpudatalist], columns=columns) + return df, cpus + except Exception as e: + print(e) + return None + +def process_cpustats(statsdf): + ''' + accepts cpu stats raw data from csv and returns a dataframe for further processing + ''' + statsdf = statsdf[['timestamp', '%idle']] + statsdf['%idle'] = pd.to_numeric(statsdf['%idle']) + statsdf['utilizationall'] = statsdf['%idle'].apply(lambda x:round(float(100) - x, 2 )) + statsdf = statsdf[['timestamp','utilizationall']] + cpu_all_Max = statsdf['utilizationall'].max() + cpu_all_Average = statsdf['utilizationall'].mean() + return statsdf, cpu_all_Max,cpu_all_Average + + +def process_memstats(df): + ''' + accepts ram stats raw data and returns a dataframe for further processing + ''' + statsdf = df[['timestamp', 'kbmemused']] + statsdf['kbmemused'] = pd.to_numeric(statsdf['kbmemused']) + statsdf['utilizationgb'] = statsdf['kbmemused'].apply(lambda x: round(x/float(1000000),2)) + statsdf = statsdf[['timestamp','utilizationgb']] + max_ram = statsdf['utilizationgb'].max() + return statsdf, max_ram diff --git a/.github/proverCiScripts/execBench.sh b/.github/proverCiScripts/execBench.sh index 72d8f5a737..1753991a49 100755 --- a/.github/proverCiScripts/execBench.sh +++ b/.github/proverCiScripts/execBench.sh @@ -29,6 +29,18 @@ case $circuit in "super") run_suffix="super_circuit_prover" ;; + "bytecode") + run_suffix="bytecode_circuit_prover" + ;; + "pi") + run_suffix="pi_circuit_prover" + ;; + "exp") + run_suffix="exp_circuit_prover" + ;; + "copy") + run_suffix="copy_circuit_prover" + ;; *) echo "No proper value" exit 1 @@ -40,3 +52,5 @@ logfile=$_date--${circuit}_bench-$k.proverlog export RUST_BACKTRACE=1 DEGREE=$k ~/.cargo/bin/cargo test --profile bench bench_${run_suffix} -p circuit-benchmarks --features benches -- --nocapture > "$target_dir/$logfile" 2>&1 + +exit 0 diff --git a/.github/proverCiScripts/getSysstat.sh b/.github/proverCiScripts/getSysstat.sh index 430469b77d..565a2525b8 100755 --- a/.github/proverCiScripts/getSysstat.sh +++ b/.github/proverCiScripts/getSysstat.sh @@ -6,22 +6,5 @@ prnumber=$1 base_dir="/home/ubuntu/CI_Prover_Benches/" target_dir="$base_dir"PR"$prnumber" -sar -uh > cpu.stats -sar -rh > mem.stats - -sed -i -e '1,5d' cpu.stats -sed -i -e '1,5d' mem.stats -sed -i -e '$ d' cpu.stats -sed -i -e '$ d' mem.stats - -minIdleCPU=$(cat cpu.stats | awk '{ print $8 }' | sed 's/%//g' | sort -n | head -1) -maxUsedCPU=$(bc <<< "scale=2; 100-$minIdleCPU") -maxMemUsed=$(cat mem.stats | awk '{ print $4 }' | sed 's/G//g' | sort -n | tail -1) - logfile=$(ls $target_dir | grep proverlog | xargs -n 1 basename) tail -12 $target_dir/$logfile - -echo "Maximum CPU Usage at $maxUsedCPU%" -echo "Maximum Mem Usage at ${maxMemUsed}Gb" - -mv $target_dir/$logfile /home/ubuntu/CI_Prover_Benches/ProverLogs/"$logfile"_PR"$prnumber" diff --git a/.github/proverCiScripts/processResults.sh b/.github/proverCiScripts/processResults.sh new file mode 100755 index 0000000000..aecfbc67a2 --- /dev/null +++ b/.github/proverCiScripts/processResults.sh @@ -0,0 +1,42 @@ +#!/bin/bash +set -e +#set -x + +prnumber=$1 +label=$2 +degree=$3 +base_dir="/home/ubuntu/CI_Prover_Benches/" +target_dir="$base_dir"PR"$prnumber" + +rm -f ~/*.stats +rm -f ~/*.proverlog +rm -f ~/*.tar.gz + +scp prover:$target_dir/*proverlog ~/ +scp ~/actions-runner/zkevm_circuits_prover/zkevm-circuits/zkevm-circuits/.github/proverCiScripts/sadf.sh prover:~/ +ssh prover "bash -s" <> cpu.stats + sadf $previousdays -d -- -r >> mem.stats + (( previousdays++ )) + done +sadf -d >> cpu.stats +sadf -d -- -r >> mem.stats diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..063329305e --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,57 @@ +### Description + +[_PR description_] + +### Issue Link + +[_link issue here_] + +### Type of change + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +### Contents + +- [_item_] + +### Rationale + +[_design decisions and extended information_] + +### How Has This Been Tested? + +[_explanation_] + +
+ +## How to fill a PR description + +Please give a concise description of your PR. + +The target readers could be future developers, reviewers, and auditors. By reading your description, they should easily understand the changes proposed in this pull request. + +MUST: Reference the issue to resolve + +### Single responsability + +Is RECOMMENDED to create single responsibility commits, but not mandatory. + +Anyway, you MUST enumerate the changes in a unitary way, e.g. + +``` +This PR contains: +- Cleanup of xxxx, yyyy +- Changed xxxx to yyyy in order to bla bla +- Added xxxx function to ... +- Refactored .... +``` + +### Design choices + +RECOMMENDED to: +- What types of design choices did you face? +- What decisions you have made? +- Any valuable information that could help reviewers to think critically diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml deleted file mode 100644 index 950aa422ea..0000000000 --- a/.github/release-drafter.yml +++ /dev/null @@ -1,29 +0,0 @@ -categories: - - title: "Changes in the bus-mapping" - label: "crate-bus-mapping" - - title: "Changes in circuit-benchmarks" - label: "crate-circuit-benchmarks" - - title: "Changes in eth-types" - label: "crate-eth-types" - - title: "Changes in external-tracer" - label: "crate-external-tracer" - - title: "Changes in gadgets" - label: "crate-gadgets" - - title: "Changes in geth-utils" - label: "crate-geth-utils" - - title: "Changes in integration-tests" - label: "crate-integration-tests" - - title: "Changes in Keccak" - label: "crate-keccak" - - title: "Changes in mock" - label: "crate-mock" - - title: "Changes in prover" - label: "crate-prover" - - title: "Changes in the zkevm-circuits" - label: "crate-zkevm-circuits" -version-resolver: - default: minor -prerelease: true -template: | - ## What’s Changed - $CHANGES diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b33df3d51..0887779a97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,30 +1,41 @@ name: CI checks on: + merge_group: pull_request: types: [synchronize, opened, reopened, ready_for_review] push: branches: - main +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + ## `actions-rs/toolchain@v1` overwrite set to false so that ## `rust-toolchain` is always used and the only source of truth. jobs: - runner: - if: github.event.pull_request.draft == false - uses: ./.github/workflows/select-runner.yml + skip_check: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + cancel_others: 'true' + concurrent_skipping: 'same_content_newer' + paths_ignore: '["**/README.md"]' test: + needs: [skip_check] + if: | + github.event.pull_request.draft == false && + (github.event.action == 'ready_for_review' || needs.skip_check.outputs.should_skip != 'true') + name: Test - needs: [runner] - runs-on: ${{ matrix.os }} - concurrency: ${{ needs.runner.outputs.concurrency-group }} - strategy: - matrix: - # We don't need to test across multiple platforms yet - # os: [ubuntu-latest, windows-latest, macOS-latest] - os: ${{ fromJSON(needs.runner.outputs.runner-matrix) }} + runs-on: ["${{github.run_id}}", self-hosted, c5.9xlarge] steps: - uses: actions/checkout@v2 @@ -34,7 +45,7 @@ jobs: - name: Setup golang uses: actions/setup-go@v3 with: - go-version: ~1.18 + go-version: ~1.19 # Go cache for building geth-utils - name: Go cache uses: actions/cache@v3 @@ -67,7 +78,10 @@ jobs: args: --verbose --release --all --all-features --exclude integration-tests --exclude circuit-benchmarks serial_ -- --ignored --test-threads 1 build: - if: github.event.pull_request.draft == false + needs: [skip_check] + if: | + github.event.pull_request.draft == false && + (github.event.action == 'ready_for_review' || needs.skip_check.outputs.should_skip != 'true') name: Build target ${{ matrix.target }} runs-on: ubuntu-latest @@ -117,7 +131,10 @@ jobs: args: --verbose --release --all-features -p circuit-benchmarks --no-run bitrot: - if: github.event.pull_request.draft == false + needs: [skip_check] + if: | + github.event.pull_request.draft == false && + (github.event.action == 'ready_for_review' || needs.skip_check.outputs.should_skip != 'true') name: Bitrot check runs-on: ubuntu-latest @@ -155,7 +172,10 @@ jobs: args: --benches --examples --all-features doc-links: - if: github.event.pull_request.draft == false + needs: [skip_check] + if: | + github.event.pull_request.draft == false && + (github.event.action == 'ready_for_review' || needs.skip_check.outputs.should_skip != 'true') name: Intra-doc links runs-on: ubuntu-latest @@ -199,7 +219,10 @@ jobs: args: --no-deps --all --document-private-items fmt: - if: github.event.pull_request.draft == false + needs: [skip_check] + if: | + github.event.pull_request.draft == false && + (github.event.action == 'ready_for_review' || needs.skip_check.outputs.should_skip != 'true') name: Rustfmt timeout-minutes: 30 diff --git a/.github/workflows/draft.yml b/.github/workflows/draft.yml deleted file mode 100644 index bb67d4a5b6..0000000000 --- a/.github/workflows/draft.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Release Drafter - -on: - push: - branches: - - main - -jobs: - update_release_draft: - runs-on: ubuntu-latest - steps: - - uses: release-drafter/release-drafter@v5 - with: - config-name: release-drafter.yml - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/gh-actions-prover-benches.yml b/.github/workflows/gh-actions-prover-benches.yml index 34a9293600..7e0199ac33 100644 --- a/.github/workflows/gh-actions-prover-benches.yml +++ b/.github/workflows/gh-actions-prover-benches.yml @@ -15,7 +15,7 @@ jobs: - run: .github/proverCiScripts/wakeUpProver.sh shell: bash - run: | - ssh prover "bash -s" -- < .github/proverCiScripts/rsSysstat.sh + ssh prover "bash -s" -- < .github/proverCiScripts/rsSysstat.sh "${{ env.PR_NUMBER }}" - run: | ssh prover "bash -s" -- < .github/proverCiScripts/prepareProver.sh "${{ env.PR_NUMBER }}" "${{ github.workspace }}" - run: .github/proverCiScripts/deployToProver.sh "${{ env.PR_NUMBER }}" "${{ github.workspace }}" @@ -25,6 +25,12 @@ jobs: shell: bash - run: | ssh prover "bash -s" -- < .github/proverCiScripts/getSysstat.sh "${{ env.PR_NUMBER }}" - - run: .github/proverCiScripts/shutdownProver.sh + - name: Calculate Benchmark Result + if: success() || failure() + run: .github/proverCiScripts/processResults.sh "${{ env.PR_NUMBER }}" '"${{ github.event.label.name }}"' "19" + shell: bash + - name: PowerOff prover + if: always() + run: .github/proverCiScripts/shutdownProver.sh shell: bash diff --git a/.github/workflows/github-ops.yml b/.github/workflows/github-ops.yml new file mode 100644 index 0000000000..b55df33546 --- /dev/null +++ b/.github/workflows/github-ops.yml @@ -0,0 +1,27 @@ +name: github-ops + +on: + workflow_dispatch: + workflow_run: + workflows: ["*"] + types: + - requested + - completed + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: true + +jobs: + ping: + runs-on: ubuntu-latest + timeout-minutes: 1 + steps: + - name: Ping runner workflow + env: + # only needs github actions (write) `workflow_dispatch` + GH_OPS_PAT: ${{ secrets.PAT_OPS_TRIGGER }} + # change `zkevm-chain.yml` to the desired workflow + run: | + curl -H "authorization: token $GH_OPS_PAT" 'https://api.github.com/repos/privacy-scaling-explorations/github-ops/actions/workflows/zkevm-circuits.yml/dispatches' -d '{"ref": "master"}' + diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 4a4bbf59e6..6839d3cb76 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -1,42 +1,58 @@ name: Integration Tests on: + merge_group: + schedule: + - cron: '50 1 * * SUN' + pull_request: + types: [synchronize, labeled] push: branches: - main + workflow_dispatch: + inputs: + provertype: + description: 'invoke real vs mock prover' + required: true + default: 'mock_prover' + type: choice + options: + - real_prover + - mock_prover + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - consecutiveness: + set-outputs: if: github.event.pull_request.draft == false runs-on: ubuntu-latest + outputs: + instancetype: ${{ steps.set-outputs.outputs.instancetype }} + provertype: ${{ steps.set-outputs.outputs.provertype }} steps: - - uses: mktcode/consecutive-workflow-action@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - - wakeuprunner: - if: github.event.pull_request.draft == false - - needs: [consecutiveness] - name: Wake up self-hosted runner - runs-on: pse-runner - - steps: - - uses: actions/checkout@v2 - - run: | - .github/integrationTestsScripts/wakeUpRunner.sh + - id: set-outputs + name: Select instance and prover type + run: | + if [ "${{ github.event.inputs.provertype }}" = "real_prover" ] || [ "${{ github.event_name }}" = "schedule" ]; then + echo "instancetype=r6i.32xlarge" >> "$GITHUB_OUTPUT" + echo "provertype=real_prover" >> "$GITHUB_OUTPUT" + elif [ "${{ github.event.inputs.provertype }}" = "mock_prover" ] || [ -z ${{ github.event.inputs.provertype }} ]; then + echo "instancetype=c5.9xlarge" >> "$GITHUB_OUTPUT" + echo "provertype=mock_prover" >> "$GITHUB_OUTPUT" + else + exit 1 + fi integration-tests: if: github.event.pull_request.draft == false - needs: [wakeuprunner] name: Integration Tests - runs-on: integration-tests-runner + runs-on: ["${{github.run_id}}", self-hosted, "${{needs.set-outputs.outputs.instancetype}}"] + needs: set-outputs - defaults: - run: - working-directory: ./integration-tests steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 @@ -45,7 +61,7 @@ jobs: - name: Setup golang uses: actions/setup-go@v3 with: - go-version: ~1.18 + go-version: ~1.19 # Go cache for building geth-utils - name: Go cache uses: actions/cache@v3 @@ -57,7 +73,7 @@ jobs: restore-keys: | ${{ runner.os }}-go- - name: Cargo cache - uses: actions/cache@v3 + uses: actions/cache@v3 with: path: | ~/.cargo/bin/ @@ -66,14 +82,20 @@ jobs: ~/.cargo/git/db/ target/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - # Run an initial build in a separate step to split the build time from execution time + # Run an initial build in a separate step to split the build time from execution time - name: Build bins run: cargo build --bin gen_blockchain_data - name: Build tests run: for testname in rpc circuit_input_builder circuits; do cargo test --profile release --test $testname --features $testname --no-run; done - run: ./run.sh --steps "setup" + working-directory: integration-tests - run: ./run.sh --steps "gendata" + working-directory: integration-tests - run: ./run.sh --steps "tests" --tests "rpc" + working-directory: integration-tests - run: ./run.sh --steps "tests" --tests "circuit_input_builder" - - run: ./run.sh --steps "tests" --tests "circuits" + working-directory: integration-tests + - run: RUST_TEST_THREADS=1 ./run.sh --steps "tests" --tests "circuits::${{ needs.set-outputs.outputs.provertype }}" + working-directory: integration-tests - run: ./run.sh --steps "cleanup" + working-directory: integration-tests diff --git a/.github/workflows/lints.yml b/.github/workflows/lints.yml index 3a5b079915..7f59474bb8 100644 --- a/.github/workflows/lints.yml +++ b/.github/workflows/lints.yml @@ -2,6 +2,7 @@ name: Lints # We only run these lints on trial-merges of PRs to reduce noise. on: + merge_group: pull_request: types: [synchronize, opened, reopened, ready_for_review] push: @@ -9,8 +10,23 @@ on: - main jobs: + skip_check: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + cancel_others: 'true' + concurrent_skipping: 'same_content_newer' + paths_ignore: '["**/README.md"]' + clippy: - if: github.event.pull_request.draft == false + needs: [skip_check] + if: | + github.event.pull_request.draft == false && + (github.event.action == 'ready_for_review' || needs.skip_check.outputs.should_skip != 'true') name: Clippy timeout-minutes: 30 diff --git a/.github/workflows/select-runner.yml b/.github/workflows/select-runner.yml deleted file mode 100644 index e309761046..0000000000 --- a/.github/workflows/select-runner.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: 'Select Runner' - -on: - workflow_call: - inputs: - enabled: - default: ${{ github.repository == 'privacy-scaling-explorations/zkevm-circuits' }} - required: false - type: boolean - - matrices: - description: 'The matrix at index 0 is intended for not running on the self-hosted runner' - default: '[["ubuntu-latest"], ["ci-checks-runner"]]' - required: false - type: string - - bastion-host: - default: pse-runner - required: false - type: string - - outputs: - runner-matrix: - value: ${{ jobs.select.outputs.matrix }} - concurrency-group: - value: ${{ jobs.select.outputs.matrix }} - -jobs: - select: - # dummy step to make github actions happy - runs-on: ubuntu-latest - steps: - - run: true - outputs: - matrix: ${{ toJSON( fromJSON(inputs.matrices)[inputs.enabled] ) }} - - wakeup: - name: Wake up self-hosted runner - if: ${{ inputs.enabled }} - needs: [select] - runs-on: ${{ inputs.bastion-host }} - concurrency: ${{ needs.select.outputs.matrix }} - steps: - - uses: actions/checkout@v2 - - run: .github/ciChecksScripts/wakeUpRunner.sh diff --git a/.github/workflows/test-features.yml b/.github/workflows/test-features.yml new file mode 100644 index 0000000000..eb43f61c97 --- /dev/null +++ b/.github/workflows/test-features.yml @@ -0,0 +1,82 @@ +name: Test feature flags + +on: + merge_group: + pull_request: + types: [synchronize, opened, reopened, ready_for_review] + push: + branches: + - main + +jobs: + skip_check: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + cancel_others: 'true' + concurrent_skipping: 'same_content_newer' + paths_ignore: '["**/README.md"]' + + test_features: + needs: [skip_check] + if: | + github.event.pull_request.draft == false && + (github.event.action == 'ready_for_review' || needs.skip_check.outputs.should_skip != 'true') + timeout-minutes: 30 + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + crate: + - zkevm-circuits + feature: + - default + - test + - test-circuits + - warn-unimplemented + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + override: false + + # Go cache for building geth-utils + - name: Go cache + uses: actions/cache@v3 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ github.workflow }}-${{ matrix.crate }}-${{ matrix.feature }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + + - name: Cargo cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ github.workflow }}-${{ matrix.crate }}-${{ matrix.feature }}-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + - name: '${{ matrix.crate }}: ${{ matrix.feature }}' + run: | + GIT_ROOT=$(pwd) + cd /tmp + cargo new foobar + cd foobar + cp "${GIT_ROOT}/rust-toolchain" . || true + cargo add --path "${GIT_ROOT}/${{ matrix.crate }}" --features '${{ matrix.feature }}' + cd ../ + rm -rf foobar + + test_features_complete: + needs: [test_features] + runs-on: ubuntu-latest + steps: + - run: echo dummy diff --git a/.gitignore b/.gitignore index 63ceefef92..3a4d0c5b8b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.png .DS_Store .vscode +.idea \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index 74c21c75cc..0000000000 --- a/CODEOWNERS +++ /dev/null @@ -1,18 +0,0 @@ -# For any file modification done to the repo, `zkevm-reviewers` team will be requested a review. -* @privacy-scaling-explorations/zkevm-reviewers - -# PRs done to `prover` workspace member will require an extra review from @pinkiebell. -prover/* @pinkiebell - -# PRs done to `mock` workspace will require an extra review from @CPerezz -mock/* @CPerezz - -# Prs done to `integration-tests` will require an extra review from @ed255 -integration-tests/* @ed255 - -# Prs done to `zkevm-circuits/state-circuit` will require an extra review from @miha-stopar -zkevm-circuits/src/state_circuit/ @miha-stopar -zkevm-circuits/src/state_circuit.rs @miha-stopar - -# Prs done in `testool` will requiere an extra review from @adria0 -testool/* @adria0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9d46c6bbe..934cbfab99 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,27 +1,93 @@ # zkEVM contribution guidelines -Thank you for investing your time in contributing to our project! +Thank you for investing your time in contributing to our project! -Before starting, we encourage you to take a look to the following documentation as it might help you in your first contribution adventure: -- https://github.com/privacy-scaling-explorations/zkevm-docs -- https://github.com/privacy-scaling-explorations/zkevm-specs +# How you can Contribute + +First take a look at our [specs](https://github.com/privacy-scaling-explorations/zkevm-specs), [auditing videos](https://www.youtube.com/watch?v=HhHTho2QZa4), and [zkevm docs](https://github.com/privacy-scaling-explorations/zkevm-docs). It’s very important that you understand at a high-level how the ZK-EVM architecture and all of its components work. + +## Best Coding Practices + +### Creating PRs + +1. Fork the zkevm or specs repos. +2. Write a simple markdown spec doc about the PR and send to the `zkevm-specs` repo. + - ******************NOTE:****************** If the PR changes the circuit behavior, it is encouraged to reflect the changes in high level python ([here](https://github.com/privacy-scaling-explorations/zkevm-specs/tree/master/src/zkevm_specs)) and submit them along the same PR with the markdown spec to `zkevm-specs` repo. +3. We encourage everyone to [open an issue](https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/new/choose) and wait until this feature/proposal gets approved by the repo maintainers before getting to work on a PR. However, this is a must for PRs that change significantly the codebase or the way on which some procedure is done (test-suite, cross-crate structures, module refactors). +4. Create a separate branch that will host all commits. Give branch names succinct title describing the change. +5. Start to make your changes. Please also make sure that the following commands pass if you have changed the code: + + ``` + make test + make clippy + ``` + +6. Once you made the changes, give the commit message a sufficient description of the change. The message content can be brief, including only enough details to summarize the purpose of the commit. In other instances, more in-depth explanations about how the commit accomplishes its goals are better suited as comments in the code. + - ******************NOTE:****************** The commits in a pull request should be organized in a manner where each commit represents a small, coherent step towards the pull request's overall objective. The structure of the pull request should facilitate the reviewer in easily tracking and understanding each change made. +7. Send the circuit PR to the `zkevm-circuits` repo. Make sure you give a clear title and succinct description of the PR and the area you are changing. + - ******************NOTE:****************** Make atomic PRs. Focused on a single feature or topic. Don't mix different topics or issues in the same PR if it can be avoided. + + +[SUGGESTION] You may run into unnecessary commits, such as merge conflicts or minor refactorings. In that case, `git rebase -i` and [squash](https://www.git-tower.com/learn/git/faq/git-squash) all your commits to one commit. + +[SUGGESTION] Rebase your branch on top of the latest main if your pull request branch is long-lived. + + + ``` + git checkout main + git pull + git checkout my/branch + git rebase main + git push -f + ``` + + +### Submitting Bug Issues + +1. If you identified a bug, please create a new issue or discuss it in our [forums](https://github.com/privacy-scaling-explorations/zkevm-circuits/discussions). +2. In the description, provide the following: + - Describe the bug + - Concrete steps to reproduce the bug + +See [this guide](https://stackoverflow.com/help/mcve) on how to create a minimal, complete, and verifiable example. + +### Submitting Feature Issues + +1. If you identified a feature, please create a new issue or discuss it in our forums. +2. In the description, provide the following: + - Describe the feature you would like + - Additional context + +### Adding Tests + +If the change being proposed alters code, it is either adding new functionality to zkevm-circuits, or fixing existing, broken functionality. In both of these cases, the pull request should include one or more tests to ensure that zkevm-circuits does not regress in the future. + +Types of tests include: + +- **Unit tests**: Functions which have very specific tasks should be unit tested. +- **Integration tests**: For general purpose, far reaching functionality, integration tests should be added. The best way to add a new integration test is to look at existing ones and follow the style. ## General considerations -- Make atomic PRs. Focused on a single feature or topic. Don't mix different topics or issues in the same PR if it can be avoided. -- For PRs that change significantly the codebase or the way on which some procedure is done (test-suite, cross-crate structures, module refactors) please file an issue and wait until this feature/proposal gets approved by the repo mantainers. -- Don't set PRs as ready for review until they're not completed from the dev perspective and also are up-to-date with `main`/`master`. Also, if any changes are requested, bring back the PR to `Draft` until it's ready again with the aformentioned requirements. + - When a PR implements a behaviour that follows a different pattern than the current design, or introduces a new design, please make sure to explain the reasoning and logic behind it. In such cases it's always better if there's an issue where that pattern / new design has been discussed and an agreement has been reached about it. -- We require at least 2 review approvals for each PR, except for the cases where the PR is considered trivial, where 1 review approval is enough. -It's up to the mantainers to decide whether more than one review is required. -- Avoid requesting reviews of a PR in `zkevm-circuits` when the implementation follows a spec that is not yet in `master` at `zkevm-specs`. In such case, set the `zkevm-circuits` PR as draft to signal you're working on it but it's not yet ready for review. -- Provide clear title and description of any PR and/or Issue you raise. That helps a lot to the reviewers/mantainers and other contributors to understand it's scope and purpose. -- The author of the PR should be the one to merge their own PR after the required approvals. Only when the author has no merge permission will a reviewer perform the merge. +- We require at least 2 review approvals for each PR, except for the cases where the PR is considered trivial, where 1 review approval is enough. It's up to the maintainers to decide whether more than one review is required. +- Avoid requesting reviews of a PR in `zkevm-circuits` when the implementation follows a spec that is not yet in `master` at `zkevm-specs`. In such case, set the `zkevm-circuits` PR as draft to signal you're working on it but it's not yet ready for review. +- The author of the PR should be the one to merge their own PR after the required approvals. Only when the author has no merge permission will a reviewer perform the merge. ## Opcodes - When working on an opcode implementation, please make sure to follow this order - 1. If the spec is not written, write it and submit a PR in `zkevm-specs` - 2. After the spec is merged, implement the opcode and submit a PR in `zkevm-circuits` + 1. If the spec is not written, write it and submit a PR in `zkevm-specs` + 2. After the spec is merged, implement the opcode and submit a PR in `zkevm-circuits` - It's OK to work on the circuit and spec at the same time and have the implementation PR submitted before the spec is merged, but in such case, please set the implementation PR as draft until the spec is merged. +- Try to include `bus-mapping` + `zkevm-circuits` opcode implementations in the same PR, but never mixing more than one Opcode at a time. + +## FAQs + +Q: Do I need permissions on PSE org to create issues or PRs? + +A: You don’t need permissions from PSE, can just create an issue or propose a PR and we will assign you issues or review/approve/merge PRs. + +Q: Is there a forum for discussing different issues or features where I can get started? -- Try to include `bus-mapping` + `zkevm-circuits` opcode implementations in the same PR, but never mixing more than one Opcode at a time. +A: There’s the issues section in zkevm repos, but for more nuanced discussion join our [Github Discussions](https://github.com/privacy-scaling-explorations/zkevm-circuits/discussions) or [discord](https://discord.com/invite/sF5CT5rzrR). diff --git a/Cargo.lock b/Cargo.lock index fd0e9e5cf4..ebe2ea3953 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,11 +20,33 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" -version = "0.7.19" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -40,9 +62,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9a8f622bcf6ff3df478e9deba3e03e4e04b300f8e6a139e192c05fa3490afc7" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" [[package]] name = "ark-std" @@ -57,9 +79,9 @@ dependencies = [ [[package]] name = "array-init" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb6d71005dc22a708c7496eee5c8dc0300ee47355de6256c3b35b12b5fef596" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" [[package]] name = "arrayref" @@ -84,9 +106,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.57" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" +checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" dependencies = [ "proc-macro2", "quote", @@ -110,7 +132,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -139,6 +161,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base58" version = "0.1.0" @@ -163,9 +191,15 @@ checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "base64ct" @@ -233,11 +267,11 @@ dependencies = [ [[package]] name = "blake2" -version = "0.10.4" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -267,7 +301,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding", + "block-padding 0.1.5", "byte-tools 0.3.1", "byteorder", "generic-array 0.12.4", @@ -279,6 +313,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ + "block-padding 0.2.1", "generic-array 0.14.6", ] @@ -300,6 +335,57 @@ dependencies = [ "byte-tools 0.3.1", ] +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "borsh" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "822462c1e7b17b31961798a6874b36daea6818e99e0cb7d3b7b0fa3c477751c3" +dependencies = [ + "borsh-derive", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh-derive" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37626c9e941a687ee9abef6065b44c379478ae563b7483c613dd705ef1dff59e" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61820b4c5693eafb998b1e67485423c923db4a75f72585c247bdee32bad81e7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c76cdbfa13def20d1f8af3ae7b3c6771f06352a74221d8851262ac384c122b8e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "bs58" version = "0.4.0" @@ -320,9 +406,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "bus-mapping" @@ -341,6 +427,7 @@ dependencies = [ "mock", "pretty_assertions", "rand", + "revm-precompile", "serde", "serde_json", "strum", @@ -351,9 +438,9 @@ dependencies = [ [[package]] name = "byte-slice-cast" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c5fdd0166095e1d463fc6cc01aa8ce547ad77a4e84d42eb6762b084e28067e" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "byte-tools" @@ -367,11 +454,32 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytecheck" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d11cac2c12b5adc6570dad2ee1b87eff4955dac476fe12d81e5fdd352e52406f" +dependencies = [ + "bytecheck_derive", + "ptr_meta", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e576ebe98e605500b3c8041bb888e966653577172df6dd97398714eb30b9bf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "bytemuck" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da" +checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393" [[package]] name = "byteorder" @@ -381,24 +489,18 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.2.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" dependencies = [ "serde", ] -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - [[package]] name = "cc" -version = "1.0.73" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -408,9 +510,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ "iana-time-zone", "js-sys", @@ -451,20 +553,9 @@ dependencies = [ [[package]] name = "clap" -version = "2.34.0" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "bitflags", - "textwrap 0.11.0", - "unicode-width", -] - -[[package]] -name = "clap" -version = "3.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed5341b2301a26ab80be5cbdced622e80ed808483c52e45e3310a877d3b37d7" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", "bitflags", @@ -474,7 +565,7 @@ dependencies = [ "once_cell", "strsim 0.10.0", "termcolor", - "textwrap 0.15.0", + "textwrap", ] [[package]] @@ -499,15 +590,48 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "cli-table" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adfbb116d9e2c4be7011360d0c0bee565712c11e969c9609b25b619366dc379d" +dependencies = [ + "cli-table-derive", + "csv", + "termcolor", + "unicode-width", +] + +[[package]] +name = "cli-table-derive" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af3bfb9da627b0a6c467624fb7963921433774ed435493b5c08a3053e829ad4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "cmake" -version = "0.1.48" +version = "0.1.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c" dependencies = [ "cc", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "coins-bip32" version = "0.7.0" @@ -517,13 +641,13 @@ dependencies = [ "bincode", "bs58", "coins-core", - "digest 0.10.3", + "digest 0.10.6", "getrandom", "hmac 0.12.1", - "k256", + "k256 0.11.6", "lazy_static", "serde", - "sha2 0.10.5", + "sha2 0.10.6", "thiserror", ] @@ -540,7 +664,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.11.0", "rand", - "sha2 0.10.5", + "sha2 0.10.6", "thiserror", ] @@ -554,14 +678,14 @@ dependencies = [ "base64 0.12.3", "bech32", "blake2", - "digest 0.10.3", + "digest 0.10.6", "generic-array 0.14.6", "hex", "ripemd", "serde", "serde_derive", - "sha2 0.10.5", - "sha3 0.10.4", + "sha2 0.10.6", + "sha3 0.10.7", "thiserror", ] @@ -590,9 +714,9 @@ checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" [[package]] name = "const-oid" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "722e23542a15cea1f65d4a1419c4cfd7a26706c70871a13a04238ca3f40f1661" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "constant_time_eq" @@ -600,6 +724,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "convert_case" version = "0.5.0" @@ -677,42 +807,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "criterion" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" -dependencies = [ - "atty", - "cast", - "clap 2.34.0", - "criterion-plot", - "csv", - "itertools", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_cbor", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" -dependencies = [ - "cast", - "itertools", -] - [[package]] name = "crossbeam-channel" version = "0.5.6" @@ -736,26 +830,24 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.10" +version = "0.9.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", "memoffset", - "once_cell", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.11" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -766,9 +858,21 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2b443d17d49dad5ef0ede301c3179cc923b8822f3393b4d2c28c269dd4a122" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array 0.14.6", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7" dependencies = [ "generic-array 0.14.6", "rand_core", @@ -820,9 +924,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ "quote", "syn", @@ -837,6 +941,50 @@ dependencies = [ "cipher", ] +[[package]] +name = "cxx" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "darling" version = "0.10.2" @@ -909,9 +1057,19 @@ dependencies = [ [[package]] name = "der" -version = "0.6.0" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "der" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" +checksum = "05e58dffcdcc8ee7b22f0c1f71a69243d7c2d9ad87b5a14361f2424a1565c219" dependencies = [ "const-oid", "zeroize", @@ -942,6 +1100,19 @@ dependencies = [ "syn", ] +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn", +] + [[package]] name = "diff" version = "0.1.13" @@ -977,11 +1148,12 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.3" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer 0.10.3", + "const-oid", "crypto-common", "subtle", ] @@ -1018,9 +1190,9 @@ dependencies = [ [[package]] name = "dunce" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541" +checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" [[package]] name = "dwrote" @@ -1037,9 +1209,8 @@ dependencies = [ [[package]] name = "ecc" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2022_09_09#2d708b4453387f03059aad68d6d87441db112a2f" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_04_20#f72db265aa3cebe297c9b9816e940d0e1d400886" dependencies = [ - "group", "integer", "num-bigint", "num-integer", @@ -1051,10 +1222,9 @@ dependencies = [ [[package]] name = "ecdsa" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2022_09_09#2d708b4453387f03059aad68d6d87441db112a2f" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_04_20#f72db265aa3cebe297c9b9816e940d0e1d400886" dependencies = [ "ecc", - "group", "num-bigint", "num-integer", "num-traits", @@ -1064,21 +1234,34 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.14.6" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] + +[[package]] +name = "ecdsa" +version = "0.16.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6f2ba6c133e1d5390e2351b10b17aa43a41209c821c98efc4ec493d16a5a91" +checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd" dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", + "der 0.7.5", + "digest 0.10.6", + "elliptic-curve 0.13.4", + "rfc6979 0.4.0", + "signature 2.1.0", ] [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" @@ -1086,16 +1269,34 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "digest 0.10.3", - "ff", + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", + "digest 0.10.6", + "ff 0.12.1", "generic-array 0.14.6", - "group", + "group 0.12.1", "pkcs8", "rand_core", - "sec1", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.1", + "digest 0.10.6", + "ff 0.13.0", + "generic-array 0.14.6", + "group 0.13.0", + "rand_core", + "sec1 0.7.1", "subtle", "zeroize", ] @@ -1117,18 +1318,29 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" -version = "0.8.31" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" dependencies = [ "cfg-if", ] +[[package]] +name = "enumn" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1940ea32e14d489b401074558be4567f35ca9507c4628b4b3fd6fe6eb2ca7b88" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", "humantime", @@ -1137,6 +1349,27 @@ dependencies = [ "termcolor", ] +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "eth-keystore" version = "0.4.2" @@ -1145,7 +1378,7 @@ checksum = "6f65b750ac950f2f825b36d08bef4cda4112e19a7b1a68f6e2bb499413e12440" dependencies = [ "aes", "ctr", - "digest 0.10.3", + "digest 0.10.6", "hex", "hmac 0.12.1", "pbkdf2 0.11.0", @@ -1153,8 +1386,8 @@ dependencies = [ "scrypt", "serde", "serde_json", - "sha2 0.10.5", - "sha3 0.10.4", + "sha2 0.10.6", + "sha3 0.10.7", "thiserror", "uuid", ] @@ -1176,7 +1409,9 @@ dependencies = [ "serde", "serde_json", "serde_with", - "sha3 0.10.4", + "sha3 0.10.7", + "strum", + "strum_macros", "subtle", "uint", ] @@ -1193,7 +1428,7 @@ dependencies = [ "regex", "serde", "serde_json", - "sha3 0.10.4", + "sha3 0.10.7", "thiserror", "uint", ] @@ -1205,7 +1440,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" dependencies = [ "crunchy", - "fixed-hash", + "fixed-hash 0.7.0", "impl-rlp", "impl-serde", "tiny-keccak", @@ -1218,10 +1453,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" dependencies = [ "ethbloom", - "fixed-hash", + "fixed-hash 0.7.0", "impl-rlp", "impl-serde", - "primitive-types", + "primitive-types 0.11.1", "uint", ] @@ -1279,13 +1514,13 @@ dependencies = [ "arrayvec", "bytes", "chrono", - "convert_case", - "elliptic-curve", + "convert_case 0.5.0", + "elliptic-curve 0.12.3", "ethabi", "fastrlp", "generic-array 0.14.6", "hex", - "k256", + "k256 0.11.6", "proc-macro2", "rand", "rlp", @@ -1309,7 +1544,7 @@ dependencies = [ "ethers-core", "getrandom", "reqwest", - "semver 1.0.13", + "semver 1.0.16", "serde", "serde-aux", "serde_json", @@ -1350,7 +1585,7 @@ checksum = "e46482e4d1e79b20c338fd9db9e166184eb387f0a4e7c05c5b5c0aa2e8c8900c" dependencies = [ "async-trait", "auto_impl", - "base64 0.13.0", + "base64 0.13.1", "ethers-core", "futures-channel", "futures-core", @@ -1388,12 +1623,12 @@ dependencies = [ "async-trait", "coins-bip32", "coins-bip39", - "elliptic-curve", + "elliptic-curve 0.12.3", "eth-keystore", "ethers-core", "hex", "rand", - "sha2 0.10.5", + "sha2 0.10.6", "thiserror", ] @@ -1417,7 +1652,7 @@ dependencies = [ "path-slash", "rayon", "regex", - "semver 1.0.13", + "semver 1.0.16", "serde", "serde_json", "solang-parser", @@ -1459,9 +1694,9 @@ dependencies = [ [[package]] name = "fastrlp-derive" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fa41ebc231af281098b11ad4a4f6182ec9096902afffe948034a20d4e1385a" +checksum = "a0f9d074ab623d1b388c12544bfeed759c7df36dc5c300cda053df9ba1232075" dependencies = [ "bytes", "proc-macro2", @@ -1471,9 +1706,20 @@ dependencies = [ [[package]] name = "ff" -version = "0.12.0" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "bitvec 1.0.1", + "rand_core", + "subtle", +] + +[[package]] +name = "ff" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df689201f395c6b90dfe87127685f8dbfc083a5e779e613575d8bd7314300c3e" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ "bitvec 1.0.1", "rand_core", @@ -1492,6 +1738,16 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1500,9 +1756,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", "miniz_oxide", @@ -1598,9 +1854,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" dependencies = [ "futures-channel", "futures-core", @@ -1613,9 +1869,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", "futures-sink", @@ -1623,15 +1879,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-executor" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" +checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" dependencies = [ "futures-core", "futures-task", @@ -1640,15 +1896,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" [[package]] name = "futures-locks" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb42d4fb72227be5778429f9ef5240a38a358925a49f05b5cf702ce7c7e558a" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" dependencies = [ "futures-channel", "futures-task", @@ -1657,9 +1913,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ "proc-macro2", "quote", @@ -1668,15 +1924,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-timer" @@ -1686,9 +1942,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-channel", "futures-core", @@ -1750,20 +2006,23 @@ checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] name = "geth-utils" version = "0.1.0" dependencies = [ + "env_logger", "gobuild", + "log", ] [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "js-sys", @@ -1784,9 +2043,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "gobuild" @@ -1799,21 +2058,31 @@ dependencies = [ [[package]] name = "group" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7391856def869c1c81063a03457c676fbcd419709c3dfb33d8d319de484b154d" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "byteorder", - "ff", + "ff 0.12.1", + "rand_core", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", "rand_core", "subtle", ] [[package]] name = "h2" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" dependencies = [ "bytes", "fnv", @@ -1828,12 +2097,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - [[package]] name = "halo2_proofs" version = "0.1.0" @@ -1841,9 +2104,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e925780549adee8364c7f2b685c753f6f3df23bde520c67416e93bf615933760" dependencies = [ "blake2b_simd", - "ff", - "group", - "pasta_curves", + "ff 0.12.1", + "group 0.12.1", + "pasta_curves 0.4.1", "plotters", "rand_core", "rayon", @@ -1853,28 +2116,31 @@ dependencies = [ [[package]] name = "halo2_proofs" version = "0.2.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2022_09_10#a9e99a72a65d7c98e8a4258c2c94269c834d1c10" +source = "git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_04_20#be955686f86eb618f55d2320c0e042485b313d22" dependencies = [ "blake2b_simd", - "ff", - "group", + "ff 0.13.0", + "group 0.13.0", "halo2curves", + "rand_chacha", "rand_core", "rayon", + "sha3 0.9.1", "tracing", ] [[package]] name = "halo2curves" -version = "0.2.1" -source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.2.1#f75ed26c961179186e9cec02cc3f841ca9e3fec1" +version = "0.3.2" +source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.2#9f5c50810bbefe779ee5cf1d852b2fe85dc35d5e" dependencies = [ - "ff", - "group", + "ff 0.13.0", + "group 0.13.0", "lazy_static", "num-bigint", "num-traits", - "pasta_curves", + "pasta_curves 0.5.1", + "paste", "rand", "rand_core", "static_assertions", @@ -1884,9 +2150,8 @@ dependencies = [ [[package]] name = "halo2wrong" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2022_09_09#2d708b4453387f03059aad68d6d87441db112a2f" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_04_20#f72db265aa3cebe297c9b9816e940d0e1d400886" dependencies = [ - "group", "halo2_proofs 0.2.0", "num-bigint", "num-integer", @@ -1895,9 +2160,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "4.3.4" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56b224eaa4987c03c30b251de7ef0c15a6a59f34222905850dbc3026dfb24d5f" +checksum = "035ef95d03713f2c347a72547b7cd38cbc9af7cd51e6099fb62d586d4a6dee3a" dependencies = [ "log", "pest", @@ -1912,6 +2177,18 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] [[package]] name = "hashers" @@ -1924,9 +2201,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -1937,12 +2214,33 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "hmac" version = "0.8.1" @@ -1959,7 +2257,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -1975,9 +2273,9 @@ dependencies = [ [[package]] name = "home" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" +checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408" dependencies = [ "winapi", ] @@ -1990,7 +2288,7 @@ checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ "bytes", "fnv", - "itoa 1.0.3", + "itoa 1.0.5", ] [[package]] @@ -2024,9 +2322,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.20" +version = "0.14.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" dependencies = [ "bytes", "futures-channel", @@ -2037,7 +2335,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.3", + "itoa 1.0.5", "pin-project-lite", "socket2", "tokio", @@ -2048,9 +2346,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.0" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http", "hyper", @@ -2061,18 +2359,28 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.48" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a0714f28b1ee39ccec0770ccb544eb02c9ef2c82bb096230eefcffa6468b0" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" dependencies = [ "android_system_properties", "core-foundation-sys", + "iana-time-zone-haiku", "js-sys", - "once_cell", "wasm-bindgen", "winapi", ] +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -2091,9 +2399,9 @@ dependencies = [ [[package]] name = "image" -version = "0.24.3" +version = "0.24.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e30ca2ecf7666107ff827a8e481de6a132a9b687ed3bb20bb1c144a36c00964" +checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" dependencies = [ "bytemuck", "byteorder", @@ -2144,12 +2452,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -2167,9 +2475,8 @@ dependencies = [ [[package]] name = "integer" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2022_09_09#2d708b4453387f03059aad68d6d87441db112a2f" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_04_20#f72db265aa3cebe297c9b9816e940d0e1d400886" dependencies = [ - "group", "maingate", "num-bigint", "num-integer", @@ -2189,9 +2496,12 @@ dependencies = [ "halo2_proofs 0.2.0", "lazy_static", "log", + "mock", "paste", "pretty_assertions", "rand_chacha", + "rand_core", + "rand_xorshift", "serde", "serde_json", "tokio", @@ -2199,17 +2509,39 @@ dependencies = [ "zkevm-circuits", ] +[[package]] +name = "io-lifetimes" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" +dependencies = [ + "libc", + "windows-sys 0.45.0", +] + [[package]] name = "ipnet" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" + +[[package]] +name = "is-terminal" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.45.0", +] [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] @@ -2222,52 +2554,69 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "jpeg-decoder" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9478aa10f73e7528198d75109c8be5cd7d15fb530238040148d5f9a22d4c5b3b" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] [[package]] name = "k256" -version = "0.11.4" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2573d3fd3e4cc741affc9b5ce1a8ce36cf29f09f80f36da4309d0ae6d7854" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" dependencies = [ "cfg-if", - "ecdsa 0.14.6", - "elliptic-curve", - "sha2 0.10.5", - "sha3 0.10.4", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.6", + "sha3 0.10.7", +] + +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa 0.16.6", + "elliptic-curve 0.13.4", + "sha2 0.10.6", ] [[package]] name = "keccak" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] [[package]] name = "keccak256" version = "0.1.0" dependencies = [ + "env_logger", "eth-types", "halo2_proofs 0.1.0", "itertools", "lazy_static", + "log", "num-bigint", "num-traits", "plotters", @@ -2277,15 +2626,15 @@ dependencies = [ [[package]] name = "lalrpop" -version = "0.19.8" +version = "0.19.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" +checksum = "f34313ec00c2eb5c3c87ca6732ea02dcf3af99c3ff7a8fb622ffb99c9d860a87" dependencies = [ "ascii-canvas", - "atty", "bit-set", "diff", "ena", + "is-terminal", "itertools", "lalrpop-util", "petgraph", @@ -2300,9 +2649,9 @@ dependencies = [ [[package]] name = "lalrpop-util" -version = "0.19.8" +version = "0.19.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" +checksum = "3d3b45d694c8074f77bc24fc26e47633c862a9cd3b48dd51209c02ba4c434d68" dependencies = [ "regex", ] @@ -2312,18 +2661,21 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "libc" -version = "0.2.132" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libloading" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ "cfg-if", "winapi", @@ -2336,7 +2688,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ "arrayref", - "base64 0.13.0", + "base64 0.13.1", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -2377,17 +2729,32 @@ dependencies = [ "libsecp256k1-core", ] +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + [[package]] name = "linked-hash-map" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + [[package]] name = "lock_api" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", @@ -2405,9 +2772,8 @@ dependencies = [ [[package]] name = "maingate" version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2022_09_09#2d708b4453387f03059aad68d6d87441db112a2f" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_04_20#f72db265aa3cebe297c9b9816e940d0e1d400886" dependencies = [ - "group", "halo2wrong", "num-bigint", "num-integer", @@ -2418,11 +2784,11 @@ dependencies = [ [[package]] name = "md-5" -version = "0.10.4" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b48670c893079d3c2ed79114e3644b7004df1c361a4e0ad52e2e6940d07c3d" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -2433,9 +2799,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.6.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ "autocfg", ] @@ -2448,23 +2814,23 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "miniz_oxide" -version = "0.5.4" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -2487,6 +2853,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "nom8" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" +dependencies = [ + "memchr", +] + [[package]] name = "num" version = "0.4.0" @@ -2515,9 +2890,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", ] @@ -2566,30 +2941,30 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] [[package]] name = "num_enum" -version = "0.5.7" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.7" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.0", "proc-macro2", "quote", "syn", @@ -2597,15 +2972,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" - -[[package]] -name = "oorandom" -version = "11.1.3" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "opaque-debug" @@ -2621,9 +2990,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "os_str_bytes" -version = "6.3.0" +version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" [[package]] name = "output_vt100" @@ -2636,9 +3005,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.1.5" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9182e4a71cae089267ab03e67c99368db7cd877baf50f931e5d6d4b71e195ac0" +checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed" dependencies = [ "arrayvec", "bitvec 1.0.1", @@ -2650,11 +3019,11 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9299338969a3d2f491d65f140b00ddec470858402f888af98e8642fb5e8965cd" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.0", "proc-macro2", "quote", "syn", @@ -2668,7 +3037,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", ] [[package]] @@ -2678,14 +3047,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.3", + "parking_lot_core 0.9.7", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if", "instant", @@ -2697,15 +3066,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -2732,13 +3101,28 @@ dependencies = [ [[package]] name = "pasta_curves" -version = "0.4.0" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc65faf8e7313b4b1fbaa9f7ca917a0eed499a9663be71477f87993604341d8" +dependencies = [ + "blake2b_simd", + "ff 0.12.1", + "group 0.12.1", + "lazy_static", + "rand", + "static_assertions", + "subtle", +] + +[[package]] +name = "pasta_curves" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "369d7785168ad7ff0cbe467d968ca3e19a927d8536b11ef9c21b4e454b15ba42" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" dependencies = [ "blake2b_simd", - "ff", - "group", + "ff 0.13.0", + "group 0.13.0", "lazy_static", "rand", "static_assertions", @@ -2747,9 +3131,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" [[package]] name = "path-slash" @@ -2782,7 +3166,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -2791,10 +3175,10 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", "hmac 0.12.1", "password-hash 0.4.2", - "sha2 0.10.5", + "sha2 0.10.6", ] [[package]] @@ -2805,9 +3189,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.3.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb779fcf4bb850fbbb0edc96ff6cf34fd90c4b1a112ce042653280d9a7364048" +checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660" dependencies = [ "thiserror", "ucd-trie", @@ -2815,9 +3199,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.3.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502b62a6d0245378b04ffe0a7fb4f4419a4815fce813bd8a0ec89a56e07d67b1" +checksum = "2ac3922aac69a40733080f53c1ce7f91dcf57e1a5f6c52f421fadec7fbdc4b69" dependencies = [ "pest", "pest_generator", @@ -2825,9 +3209,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.3.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451e629bf49b750254da26132f1a5a9d11fd8a95a3df51d15c4abd1ba154cb6c" +checksum = "d06646e185566b5961b4058dd107e0a7f56e77c3f484549fb119867773c0f202" dependencies = [ "pest", "pest_meta", @@ -2838,20 +3222,20 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.3.1" +version = "2.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcec162c71c45e269dfc3fc2916eaeb97feab22993a21bcce4721d08cd7801a6" +checksum = "e6f60b2ba541577e2a0c307c8f39d1439108120eb7903adeb6497fa880c59616" dependencies = [ "once_cell", "pest", - "sha1", + "sha2 0.10.6", ] [[package]] name = "petgraph" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", "indexmap", @@ -2955,15 +3339,15 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ - "der", + "der 0.6.1", "spki", ] [[package]] name = "pkg-config" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "plotters" @@ -3013,9 +3397,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.6" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f0e7f4c94ec26ff209cee506314212639d6c91b80afb82984819fafce9df01c" +checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" dependencies = [ "bitflags", "crc32fast", @@ -3023,11 +3407,20 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "poseidon" +version = "0.2.0" +source = "git+https://github.com/privacy-scaling-explorations/poseidon.git?tag=v2023_04_20#807f8f555313f726ca03bdf941f798098f488ba4" +dependencies = [ + "halo2curves", + "subtle", +] + [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "precomputed-hash" @@ -3049,13 +3442,13 @@ dependencies = [ [[package]] name = "prettytable-rs" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f375cb74c23b51d23937ffdeb48b1fbf5b6409d4b9979c1418c1de58bc8f801" +checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" dependencies = [ - "atty", "csv", "encode_unicode", + "is-terminal", "lazy_static", "term", "unicode-width", @@ -3067,24 +3460,42 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" dependencies = [ - "fixed-hash", + "fixed-hash 0.7.0", "impl-codec", "impl-rlp", "impl-serde", "uint", ] +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash 0.8.0", + "uint", +] + [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ - "once_cell", - "thiserror", "toml", ] +[[package]] +name = "proc-macro-crate" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" +dependencies = [ + "once_cell", + "toml_edit", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -3111,24 +3522,44 @@ dependencies = [ [[package]] name = "proc-macro-hack" -version = "0.5.19" +version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.43" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -3168,9 +3599,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] @@ -3186,21 +3617,19 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.3" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" dependencies = [ - "autocfg", - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.3" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -3230,9 +3659,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", @@ -3243,21 +3672,30 @@ dependencies = [ name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] -name = "regex-syntax" -version = "0.6.27" +name = "rend" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "79af64b4b6362ffba04eef3a4e10829718a4896dac19daa741851c86781edf95" +dependencies = [ + "bytecheck", +] [[package]] name = "reqwest" -version = "0.11.11" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" +checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" dependencies = [ - "base64 0.13.0", + "base64 0.21.0", "bytes", "encoding_rs", "futures-core", @@ -3269,9 +3707,9 @@ dependencies = [ "hyper-rustls", "ipnet", "js-sys", - "lazy_static", "log", "mime", + "once_cell", "percent-encoding", "pin-project-lite", "rustls", @@ -3290,17 +3728,65 @@ dependencies = [ "winreg", ] +[[package]] +name = "revm-precompile" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a3eabf08ea9e4063f5531b8735e29344d9d6eaebaa314c58253f6c17fcdf2d" +dependencies = [ + "k256 0.13.1", + "num", + "once_cell", + "revm-primitives", + "ripemd", + "secp256k1", + "sha2 0.10.6", + "sha3 0.10.7", + "substrate-bn", +] + +[[package]] +name = "revm-primitives" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180427e1169b860ab63eaa5bcff158010073646abf3312aed11a1d7aa1aa8291" +dependencies = [ + "auto_impl", + "bitvec 1.0.1", + "bytes", + "derive_more", + "enumn", + "fixed-hash 0.8.0", + "hashbrown 0.13.2", + "hex", + "hex-literal", + "primitive-types 0.12.1", + "rlp", + "ruint", + "sha3 0.10.7", +] + [[package]] name = "rfc6979" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c86280f057430a52f4861551b092a01b419b8eacefc7c995eacb9dc132fe32" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ - "crypto-bigint", + "crypto-bigint 0.4.9", "hmac 0.12.1", "zeroize", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -3318,18 +3804,43 @@ dependencies = [ [[package]] name = "ripemd" -version = "0.1.1" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "rkyv" +version = "0.7.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec2b3485b07d96ddfd3134767b8a447b45ea4eb91448d0a35180ec0ffd5ed15" +dependencies = [ + "bytecheck", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1facec54cb5e0dc08553501fa740091086d0259ad0067e0d4103448e4cb22ed3" +checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4" dependencies = [ - "digest 0.10.3", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "rlp" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999508abb0ae792aabed2460c45b89106d97fe4adac593bdaef433c2605847b5" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", "rustc-hex", @@ -3346,15 +3857,42 @@ dependencies = [ "syn", ] +[[package]] +name = "ruint" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d470e29e933dac4101180fd6574971892315c414cf2961a192729089687cc9b" +dependencies = [ + "derive_more", + "primitive-types 0.11.1", + "rlp", + "ruint-macro", + "rustc_version 0.4.0", + "thiserror", +] + +[[package]] +name = "ruint-macro" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62cc5760263ea229d367e7dff3c0cbf09e4797a125bd87059a6c095804f3b2d1" + [[package]] name = "rust_decimal" -version = "1.26.1" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee9164faf726e4f3ece4978b25ca877ddc6802fa77f38cdccb32c7f805ecd70c" +checksum = "e13cf35f7140155d02ba4ec3294373d513a3c7baa8364c162b030e33c61520a8" dependencies = [ "arrayvec", + "borsh", + "bytecheck", + "byteorder", + "bytes", "num-traits", + "rand", + "rkyv", "serde", + "serde_json", ] [[package]] @@ -3378,14 +3916,28 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.13", + "semver 1.0.16", +] + +[[package]] +name = "rustix" +version = "0.36.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", ] [[package]] name = "rustls" -version = "0.20.6" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -3395,24 +3947,24 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.13.0", + "base64 0.21.0", ] [[package]] name = "rustversion" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "salsa20" @@ -3438,6 +3990,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" + [[package]] name = "scrypt" version = "0.8.1" @@ -3448,7 +4006,7 @@ dependencies = [ "password-hash 0.3.2", "pbkdf2 0.10.1", "salsa20", - "sha2 0.10.5", + "sha2 0.10.6", ] [[package]] @@ -3461,20 +4019,57 @@ dependencies = [ "untrusted", ] +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + [[package]] name = "sec1" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "base16ct", - "der", + "base16ct 0.1.1", + "der 0.6.1", "generic-array 0.14.6", "pkcs8", "subtle", "zeroize", ] +[[package]] +name = "sec1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.5", + "generic-array 0.14.6", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + [[package]] name = "semver" version = "0.11.0" @@ -3486,9 +4081,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.13" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" dependencies = [ "serde", ] @@ -3504,15 +4099,15 @@ dependencies = [ [[package]] name = "send_wrapper" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930c0acf610d3fdb5e2ab6213019aaa04e227ebe9547b0649ba599b16d788bd7" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.144" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" dependencies = [ "serde_derive", ] @@ -3527,21 +4122,11 @@ dependencies = [ "serde_json", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" -version = "1.0.144" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", @@ -3550,11 +4135,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.85" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +checksum = "7434af0dc1cbd59268aa98b4c22c131c0584d2232f6fb166efb993e2832e896a" dependencies = [ - "itoa 1.0.3", + "itoa 1.0.5", "ryu", "serde", ] @@ -3566,7 +4151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.3", + "itoa 1.0.5", "ryu", "serde", ] @@ -3595,24 +4180,13 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.3", -] - -[[package]] -name = "sha1" -version = "0.10.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -3642,13 +4216,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9db03534dff993187064c4e0c05a5708d2a9728ace9a8959b77bedf415dac5" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest 0.10.6", ] [[package]] @@ -3665,21 +4239,43 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.4" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha3" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaedf34ed289ea47c2b741bb72e5357a209512d67bcd4bda44359e5bf0470f56" +checksum = "54c2bb1a323307527314a36bfb73f24febb08ce2b8a554bf4ffd6f51ad15198c" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", "keccak", ] [[package]] name = "signature" -version = "1.6.1" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest 0.10.6", + "rand_core", +] + +[[package]] +name = "signature" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90531723b08e4d6d71b791108faf51f03e1b4a7784f96b2b87f852ebc247228" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ - "digest 0.10.3", + "digest 0.10.6", "rand_core", ] @@ -3700,9 +4296,27 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "snark-verifier" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/snark-verifier?tag=v2023_04_20#e5d5e4a6ccff2bba71baf77ab7a12b124d6364a1" +dependencies = [ + "ecc", + "halo2_proofs 0.2.0", + "halo2curves", + "hex", + "itertools", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits", + "poseidon", + "rand", +] [[package]] name = "socket2" @@ -3740,7 +4354,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", - "der", + "der 0.6.1", ] [[package]] @@ -3796,6 +4410,19 @@ dependencies = [ "syn", ] +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand", + "rustc-hex", +] + [[package]] name = "subtle" version = "2.4.1" @@ -3804,9 +4431,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.99" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -3843,9 +4470,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -3856,13 +4483,14 @@ version = "0.1.0" dependencies = [ "anyhow", "bus-mapping", - "clap 3.2.21", + "clap", "env_logger", "eth-types", "ethers-core", "ethers-signers", "external-tracer", "glob", + "halo2_proofs 0.2.0", "handlebars", "hex", "keccak256", @@ -3870,6 +4498,8 @@ dependencies = [ "mock", "once_cell", "prettytable-rs", + "rand", + "rand_chacha", "rayon", "regex", "serde", @@ -3878,39 +4508,31 @@ dependencies = [ "strum_macros", "thiserror", "toml", + "urlencoding", "yaml-rust", "zkevm-circuits", ] [[package]] name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "textwrap" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.34" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1b05ca9d106ba7d2e31a9dab4a64e7be2cce415321966ea3132c49a656e252" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.34" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8f2591983642de85c921015f3f070c665a197ed69e417af436115e3a1407487" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -3919,9 +4541,9 @@ dependencies = [ [[package]] name = "time" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", @@ -3937,16 +4559,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -3958,15 +4570,15 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.21.1" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0020c875007ad96677dcc890298f4b942882c5d4eb7cc8f439fc3bf813dc9c95" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" dependencies = [ "autocfg", "bytes", @@ -3974,18 +4586,17 @@ dependencies = [ "memchr", "mio", "num_cpus", - "once_cell", "pin-project-lite", "socket2", "tokio-macros", - "winapi", + "windows-sys 0.42.0", ] [[package]] name = "tokio-macros" -version = "1.8.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", @@ -4035,13 +4646,30 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" + +[[package]] +name = "toml_edit" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" +dependencies = [ + "indexmap", + "nom8", + "toml_datetime", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -4050,9 +4678,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.36" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", @@ -4062,9 +4690,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", @@ -4073,9 +4701,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", ] @@ -4092,9 +4720,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "ttf-parser" @@ -4108,7 +4736,7 @@ version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" dependencies = [ - "base64 0.13.0", + "base64 0.13.1", "byteorder", "bytes", "http", @@ -4125,9 +4753,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" @@ -4137,9 +4765,9 @@ checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "uint" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ "byteorder", "crunchy", @@ -4149,36 +4777,36 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-normalization" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "untrusted" @@ -4197,6 +4825,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9" + [[package]] name = "utf-8" version = "0.7.6" @@ -4254,9 +4888,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4264,9 +4898,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -4279,9 +4913,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if", "js-sys", @@ -4291,9 +4925,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4301,9 +4935,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -4314,9 +4948,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-timer" @@ -4335,9 +4969,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -4355,9 +4989,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.4" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ "webpki", ] @@ -4401,46 +5035,84 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.36.1" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ + "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", + "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "winreg" @@ -4462,13 +5134,14 @@ dependencies = [ [[package]] name = "ws_stream_wasm" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47ca1ab42f5afed7fc332b22b6e932ca5414b209465412c8cdf0ad23bc0de645" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" dependencies = [ "async_io_stream", "futures", "js-sys", + "log", "pharos", "rustc_version 0.4.0", "send_wrapper", @@ -4480,9 +5153,9 @@ dependencies = [ [[package]] name = "wyz" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] @@ -4526,7 +5199,7 @@ version = "0.1.0" dependencies = [ "array-init", "bus-mapping", - "criterion", + "cli-table", "ctor", "ecc", "ecdsa 0.1.0", @@ -4554,8 +5227,8 @@ dependencies = [ "rand_xorshift", "serde", "serde_json", - "sha3 0.10.4", + "sha3 0.10.7", + "snark-verifier", "strum", "strum_macros", - "subtle", ] diff --git a/Cargo.toml b/Cargo.toml index 830e7f7119..be096fc2fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ ] [patch.crates-io] -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_09_10" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } # Definition of benchmarks profile to use. [profile.bench] @@ -34,4 +34,4 @@ debug-assertions = true overflow-checks = true rpath = false lto = "thin" -incremental = false +incremental = true diff --git a/Makefile b/Makefile index 2dd29cd583..6dcf6e8420 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,10 @@ +CARGO = cargo + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Darwin) + CARGO += --config 'build.rustdocflags = ["-C", "link-args=-framework CoreFoundation -framework Security"]' +endif + help: ## Display this help screen @grep -h \ -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ @@ -20,33 +27,54 @@ test: ## Run tests for all the workspace members # Run heavy tests serially to avoid OOM @cargo test --release --all --all-features --exclude integration-tests --exclude circuit-benchmarks serial_ -- --ignored --test-threads 1 + test_doc: ## Test the docs - @cargo test --release --all --all-features --doc + @$(CARGO) test --release --all --all-features --doc test_benches: ## Compiles the benchmarks @cargo test --verbose --release --all-features -p circuit-benchmarks --no-run test-all: fmt doc clippy test_doc test_benches test ## Run all the CI checks locally (in your actual toolchain) +super_bench: ## Run Super Circuit benchmarks + @cargo test --profile bench bench_super_circuit_prover -p circuit-benchmarks --features benches -- --nocapture + evm_bench: ## Run Evm Circuit benchmarks @cargo test --profile bench bench_evm_circuit_prover -p circuit-benchmarks --features benches -- --nocapture state_bench: ## Run State Circuit benchmarks @cargo test --profile bench bench_state_circuit_prover -p circuit-benchmarks --features benches -- --nocapture -bit_keccak_bench: ## Run Bit Keccak Circuit benchmarks - @cargo test --profile bench bench_bit_keccak_circuit_prover -p circuit-benchmarks --features benches -- --nocapture - -packed_keccak_bench: ## Run Packed Keccak Circuit benchmarks - @cargo test --profile bench bench_packed_keccak_circuit_prover -p circuit-benchmarks --features benches -- --nocapture - packed_multi_keccak_bench: ## Run Packed Multi Keccak Circuit benchmarks @cargo test --profile bench bench_packed_multi_keccak_circuit_prover -p circuit-benchmarks --features benches -- --nocapture bytecode_bench: ## Run Bytecode Circuit benchmarks @cargo test --profile bench bench_bytecode_circuit_prover -p circuit-benchmarks --features benches -- --nocapture +pi_bench: ## Run Public Input Circuit benchmarks + @cargo test --profile bench bench_pi_circuit_prover -p circuit-benchmarks --features benches -- --nocapture + +copy_bench: ## Run Copy Circuit benchmarks + @cargo test --profile bench bench_copy_circuit_prover -p circuit-benchmarks --features benches -- --nocapture + +tx_bench: ## Run Tx Circuit benchmarks + @cargo test --profile bench bench_tx_circuit_prover -p circuit-benchmarks --features benches -- --nocapture + +exp_bench: ## Run Exp Circuit benchmarks + @cargo test --profile bench bench_exp_circuit_prover -p circuit-benchmarks --features benches -- --nocapture + circuit_benches: evm_bench state_bench ## Run All Circuit benchmarks +stats_state_circuit: # Print a table with State Circuit stats by ExecState/opcode + @cargo run --bin stats --features stats -- state + +stats_evm_circuit: # Print a table with EVM Circuit stats by ExecState/opcode + @cargo run --bin stats --features stats -- evm + +stats_copy_circuit: # Print a table with Copy Circuit stats by ExecState/opcode + @cargo run --bin stats --features stats -- copy + +evm_exec_steps_occupancy: # Print a table for each EVM-CellManager CellType with the top 10 occupancy ExecutionSteps associated + @cargo run --bin stats --features stats -- exec -.PHONY: clippy doc fmt test test_benches test-all evm_bench state_bench circuit_benches help +.PHONY: clippy doc fmt test test_benches test-all evm_bench state_bench circuit_benches evm_exec_steps_occupancy stats_state_circuit stats_evm_circuit stats_copy_circuit help diff --git a/README.md b/README.md index 3477ad9537..260eec36b5 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,13 @@ to use for your circuit in the bench process. - State Circuit prover benches. -> `DEGREE=18 make state_bench` You can also run all benchmarks by running: `make circuit_benches DEGREE=18`. + +## GH Actions Benchmark Results + +Circuit Benchmark Results are accessible here: https://grafana.zkevm-testnet.org/d/vofy8DAVz/circuit-benchmarks?orgId=1 + +- circuit_benchmarks panel displays: + - overall test result + - timers and system statistics + - url for downloading prover log and sys stat files + - clickable sysstats_url element that loads the memory and cpu utilization profiles for the given test diff --git a/bus-mapping/Cargo.toml b/bus-mapping/Cargo.toml index 740ce57505..00204bf9b5 100644 --- a/bus-mapping/Cargo.toml +++ b/bus-mapping/Cargo.toml @@ -13,7 +13,7 @@ mock = { path = "../mock", optional = true } ethers-core = "0.17.0" ethers-providers = "0.17.0" -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_09_10" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } itertools = "0.10" lazy_static = "1.4" log = "0.4.14" @@ -23,6 +23,8 @@ serde_json = "1.0.66" strum = "0.24" strum_macros = "0.24" +revm-precompile = "2.0.2" + [dev-dependencies] hex = "0.4.3" pretty_assertions = "1.0.0" diff --git a/bus-mapping/README.md b/bus-mapping/README.md index 72ca8e53c0..e0cbea24da 100644 --- a/bus-mapping/README.md +++ b/bus-mapping/README.md @@ -109,7 +109,7 @@ let block_ctants = BlockConstants::new( pasta_curves::Fp::zero(), ); -// Here we have the ExecutionTrace completelly formed with all of the data to witness structured. +// Here we have the ExecutionTrace completely formed with all of the data to witness structured. let obtained_exec_trace = ExecutionTrace::from_trace_bytes( input_trace.as_bytes(), block_ctants, diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 6c67ed2df5..11e676d561 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -11,24 +11,83 @@ mod tracer_tests; mod transaction; use self::access::gen_state_access_trace; -use crate::error::Error; -use crate::evm::opcodes::{gen_associated_ops, gen_begin_tx_ops, gen_end_tx_ops}; -use crate::operation::{CallContextField, RW}; -use crate::rpc::GethClient; -use crate::state_db::{self, CodeDB, StateDB}; +use crate::{ + error::Error, + evm::opcodes::{gen_associated_ops, gen_associated_steps}, + operation::{CallContextField, Operation, RWCounter, StartOp, RW}, + rpc::GethClient, + state_db::{self, CodeDB, StateDB}, +}; pub use access::{Access, AccessSet, AccessValue, CodeSource}; pub use block::{Block, BlockContext}; pub use call::{Call, CallContext, CallKind}; use core::fmt::Debug; -use eth_types::sign_types::{pk_bytes_le, pk_bytes_swap_endianness, SignData}; -use eth_types::{self, geth_types, Address, GethExecStep, GethExecTrace, Word}; +use eth_types::{ + self, geth_types, + sign_types::{pk_bytes_le, pk_bytes_swap_endianness, SignData}, + Address, GethExecStep, GethExecTrace, ToWord, Word, +}; use ethers_providers::JsonRpcClient; -pub use execution::{CopyDataType, CopyEvent, CopyStep, ExecState, ExecStep, NumberOrHash}; +pub use execution::{ + CopyDataType, CopyEvent, CopyStep, ExecState, ExecStep, ExpEvent, ExpStep, NumberOrHash, +}; pub use input_state_ref::CircuitInputStateRef; use itertools::Itertools; +use log::warn; use std::collections::HashMap; pub use transaction::{Transaction, TransactionContext}; +/// Circuit Setup Parameters +#[derive(Debug, Clone, Copy)] +pub struct CircuitsParams { + /// Maximum number of rw operations in the state circuit (RwTable length / + /// nummber of rows). This must be at least the number of rw operations + /// + 1, in order to allocate at least a Start row. + pub max_rws: usize, + // TODO: evm_rows: Maximum number of rows in the EVM Circuit + /// Maximum number of txs in the Tx Circuit + pub max_txs: usize, + /// Maximum number of bytes from all txs calldata in the Tx Circuit + pub max_calldata: usize, + /// Max ammount of rows that the CopyCircuit can have. + pub max_copy_rows: usize, + /// Max number of steps that the ExpCircuit can have. Each step is further + /// expressed in 7 rows + pub max_exp_steps: usize, + /// Maximum number of bytes supported in the Bytecode Circuit + pub max_bytecode: usize, + /// Pad evm circuit number of rows. + /// When 0, the EVM circuit number of rows will be dynamically calculated, + /// so the same circuit will not be able to proof different witnesses. + /// In this case it will contain as many rows for all steps + 1 row + /// for EndBlock. + pub max_evm_rows: usize, + /// Pad the keccak circuit with this number of invocations to a static + /// capacity. Number of keccak_f that the Keccak circuit will support. + /// When 0, the Keccak circuit number of rows will be dynamically + /// calculated, so the same circuit will not be able to prove different + /// witnesses. + pub max_keccak_rows: usize, +} + +impl Default for CircuitsParams { + /// Default values for most of the unit tests of the Circuit Parameters + fn default() -> Self { + CircuitsParams { + max_rws: 1000, + max_txs: 1, + max_calldata: 256, + // TODO: Check whether this value is correct or we should increase/decrease based on + // this lib tests + max_copy_rows: 1000, + max_exp_steps: 1000, + max_bytecode: 512, + max_evm_rows: 0, + max_keccak_rows: 0, + } + } +} + /// Builder to generate a complete circuit input from data gathered from a geth /// instance. This structure is the centre of the crate and is intended to be /// the only entry point to it. The `CircuitInputBuilder` works in several @@ -145,9 +204,58 @@ impl<'a> CircuitInputBuilder { self.handle_tx(tx, geth_trace, tx_index + 1 == eth_block.transactions.len())?; } self.set_value_ops_call_context_rwc_eor(); + self.set_end_block(); Ok(()) } + fn set_end_block(&mut self) { + let max_rws = self.block.circuits_params.max_rws; + let mut end_block_not_last = self.block.block_steps.end_block_not_last.clone(); + let mut end_block_last = self.block.block_steps.end_block_last.clone(); + end_block_not_last.rwc = self.block_ctx.rwc; + end_block_last.rwc = self.block_ctx.rwc; + + let mut dummy_tx = Transaction::default(); + let mut dummy_tx_ctx = TransactionContext::default(); + let mut state = self.state_ref(&mut dummy_tx, &mut dummy_tx_ctx); + + if let Some(call_id) = state.block.txs.last().map(|tx| tx.calls[0].call_id) { + state.call_context_read( + &mut end_block_last, + call_id, + CallContextField::TxId, + Word::from(state.block.txs.len() as u64), + ); + } + + let mut push_op = |step: &mut ExecStep, rwc: RWCounter, rw: RW, op: StartOp| { + let op_ref = state.block.container.insert(Operation::new(rwc, rw, op)); + step.bus_mapping_instance.push(op_ref); + }; + + let total_rws = state.block_ctx.rwc.0 - 1; + // We need at least 1 extra Start row + #[allow(clippy::int_plus_one)] + { + assert!( + total_rws + 1 <= max_rws, + "total_rws + 1 <= max_rws, total_rws={}, max_rws={}", + total_rws, + max_rws + ); + } + push_op(&mut end_block_last, RWCounter(1), RW::READ, StartOp {}); + push_op( + &mut end_block_last, + RWCounter(max_rws - total_rws), + RW::READ, + StartOp {}, + ); + + self.block.block_steps.end_block_not_last = end_block_not_last; + self.block.block_steps.end_block_last = end_block_last; + } + /// Handle a transaction with its corresponding execution trace to generate /// all the associated operations. Each operation is registered in /// `self.block.container`, and each step stores the @@ -162,11 +270,11 @@ impl<'a> CircuitInputBuilder { let mut tx = self.new_tx(eth_tx, !geth_trace.failed)?; let mut tx_ctx = TransactionContext::new(eth_tx, geth_trace, is_last_tx)?; - // TODO: Move into gen_associated_steps with - // - execution_state: BeginTx - // - op: None // Generate BeginTx step - let begin_tx_step = gen_begin_tx_ops(&mut self.state_ref(&mut tx, &mut tx_ctx))?; + let begin_tx_step = gen_associated_steps( + &mut self.state_ref(&mut tx, &mut tx_ctx), + ExecState::BeginTx, + )?; tx.steps_mut().push(begin_tx_step); for (index, geth_step) in geth_trace.struct_logs.iter().enumerate() { @@ -180,11 +288,9 @@ impl<'a> CircuitInputBuilder { tx.steps_mut().extend(exec_steps); } - // TODO: Move into gen_associated_steps with - // - execution_state: EndTx - // - op: None // Generate EndTx step - let end_tx_step = gen_end_tx_ops(&mut self.state_ref(&mut tx, &mut tx_ctx))?; + let end_tx_step = + gen_associated_steps(&mut self.state_ref(&mut tx, &mut tx_ctx), ExecState::EndTx)?; tx.steps_mut().push(end_tx_step); self.sdb.commit_tx(); @@ -192,27 +298,24 @@ impl<'a> CircuitInputBuilder { Ok(()) } +} - /// Return all the keccak inputs used during the processing of the current - /// block. - pub fn keccak_inputs(&self) -> Result>, Error> { - let mut keccak_inputs = Vec::new(); - // Tx Circuit - let txs: Vec = self.block.txs.iter().map(|tx| tx.into()).collect(); - keccak_inputs.extend_from_slice(&keccak_inputs_tx_circuit( - &txs, - self.block.chain_id.as_u64(), - )?); - // Bytecode Circuit - for bytecode in self.code_db.0.values() { - keccak_inputs.push(bytecode.clone()); - } - // EVM Circuit - keccak_inputs.extend_from_slice(&self.block.sha3_inputs); - // MPT Circuit - // TODO https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/696 - Ok(keccak_inputs) +/// Return all the keccak inputs used during the processing of the current +/// block. +pub fn keccak_inputs(block: &Block, code_db: &CodeDB) -> Result>, Error> { + let mut keccak_inputs = Vec::new(); + // Tx Circuit + let txs: Vec = block.txs.iter().map(|tx| tx.tx.clone()).collect(); + keccak_inputs.extend_from_slice(&keccak_inputs_tx_circuit(&txs, block.chain_id.as_u64())?); + // Bytecode Circuit + for bytecode in code_db.0.values() { + keccak_inputs.push(bytecode.clone()); } + // EVM Circuit + keccak_inputs.extend_from_slice(&block.sha3_inputs); + // MPT Circuit + // TODO https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/696 + Ok(keccak_inputs) } /// Generate the keccak inputs required by the SignVerify Chip from the @@ -237,7 +340,19 @@ pub fn keccak_inputs_tx_circuit( chain_id: u64, ) -> Result>, Error> { let mut inputs = Vec::new(); - let sign_datas: Vec = txs.iter().map(|tx| tx.sign_data(chain_id)).try_collect()?; + let sign_datas: Vec = txs + .iter() + .enumerate() + .filter(|(i, tx)| { + if tx.v == 0 && tx.r.is_zero() && tx.s.is_zero() { + warn!("tx {} is not signed, skipping tx circuit keccak input", i); + false + } else { + true + } + }) + .map(|(_, tx)| tx.sign_data(chain_id)) + .try_collect()?; // Keccak inputs from SignVerify Chip let sign_verify_inputs = keccak_inputs_sign_verify(&sign_datas); inputs.extend_from_slice(&sign_verify_inputs); @@ -247,14 +362,21 @@ pub fn keccak_inputs_tx_circuit( } /// Retrieve the init_code from memory for {CREATE, CREATE2} -pub fn get_create_init_code<'a, 'b>( +pub fn get_create_init_code<'a>( call_ctx: &'a CallContext, - step: &'b GethExecStep, + step: &GethExecStep, ) -> Result<&'a [u8], Error> { - let offset = step.stack.nth_last(1)?; - let length = step.stack.nth_last(2)?; - Ok(&call_ctx.memory.0 - [offset.low_u64() as usize..(offset.low_u64() + length.low_u64()) as usize]) + let offset = step.stack.nth_last(1)?.low_u64() as usize; + let length = step.stack.nth_last(2)?.as_usize(); + + let mem_len = call_ctx.memory.0.len(); + if offset >= mem_len { + return Ok(&[]); + } + + let offset_end = offset.checked_add(length).unwrap_or(mem_len); + + Ok(&call_ctx.memory.0[offset..offset_end]) } /// Retrieve the memory offset and length of call. @@ -276,55 +398,126 @@ type EthBlock = eth_types::Block; pub struct BuilderClient { cli: GethClient

, chain_id: Word, - history_hashes: Vec, + circuits_params: CircuitsParams, +} + +/// Get State Accesses from TxExecTraces +pub fn get_state_accesses( + eth_block: &EthBlock, + geth_traces: &[eth_types::GethExecTrace], +) -> Result { + let mut block_access_trace = vec![Access::new( + None, + RW::WRITE, + AccessValue::Account { + address: eth_block + .author + .ok_or(Error::EthTypeError(eth_types::Error::IncompleteBlock))?, + }, + )]; + for (tx_index, tx) in eth_block.transactions.iter().enumerate() { + let geth_trace = &geth_traces[tx_index]; + let tx_access_trace = gen_state_access_trace(eth_block, tx, geth_trace)?; + block_access_trace.extend(tx_access_trace); + } + + Ok(AccessSet::from(block_access_trace)) +} + +/// Build a partial StateDB from step 3 +pub fn build_state_code_db( + proofs: Vec, + codes: HashMap>, +) -> (StateDB, CodeDB) { + let mut sdb = StateDB::new(); + for proof in proofs { + let mut storage = HashMap::new(); + for storage_proof in proof.storage_proof { + storage.insert(storage_proof.key, storage_proof.value); + } + sdb.set_account( + &proof.address, + state_db::Account { + nonce: proof.nonce.as_u64(), + balance: proof.balance, + storage, + code_hash: proof.code_hash, + }, + ) + } + + let mut code_db = CodeDB::new(); + for (_address, code) in codes { + code_db.insert(code.clone()); + } + (sdb, code_db) } impl BuilderClient

{ /// Create a new BuilderClient - pub async fn new(client: GethClient

) -> Result { + pub async fn new( + client: GethClient

, + circuits_params: CircuitsParams, + ) -> Result { let chain_id = client.get_chain_id().await?; Ok(Self { cli: client, chain_id: chain_id.into(), - // TODO: Get history hashes - history_hashes: Vec::new(), + circuits_params, }) } - /// Step 1. Query geth for Block, Txs and TxExecTraces + /// Step 1. Query geth for Block, Txs, TxExecTraces, history block hashes + /// and previous state root. pub async fn get_block( &self, block_num: u64, - ) -> Result<(EthBlock, Vec), Error> { + ) -> Result<(EthBlock, Vec, Vec, Word), Error> { let eth_block = self.cli.get_block_by_number(block_num.into()).await?; let geth_traces = self.cli.trace_block_by_number(block_num.into()).await?; - Ok((eth_block, geth_traces)) + // fetch up to 256 blocks + let mut n_blocks = std::cmp::min(256, block_num as usize); + let mut next_hash = eth_block.parent_hash; + let mut prev_state_root: Option = None; + let mut history_hashes = vec![Word::default(); n_blocks]; + while n_blocks > 0 { + n_blocks -= 1; + + // TODO: consider replacing it with `eth_getHeaderByHash`, it's faster + let header = self.cli.get_block_by_hash(next_hash).await?; + + // set the previous state root + if prev_state_root.is_none() { + prev_state_root = Some(header.state_root.to_word()); + } + + // latest block hash is the last item + let block_hash = header + .hash + .ok_or(Error::EthTypeError(eth_types::Error::IncompleteBlock))? + .to_word(); + history_hashes[n_blocks] = block_hash; + + // continue + next_hash = header.parent_hash; + } + + Ok(( + eth_block, + geth_traces, + history_hashes, + prev_state_root.unwrap_or_default(), + )) } /// Step 2. Get State Accesses from TxExecTraces pub fn get_state_accesses( - &self, eth_block: &EthBlock, geth_traces: &[eth_types::GethExecTrace], ) -> Result { - let mut block_access_trace = vec![Access::new( - None, - RW::WRITE, - AccessValue::Account { - address: eth_block - .author - .ok_or(Error::EthTypeError(eth_types::Error::IncompleteBlock))?, - }, - )]; - for (tx_index, tx) in eth_block.transactions.iter().enumerate() { - let geth_trace = &geth_traces[tx_index]; - let tx_access_trace = gen_state_access_trace(eth_block, tx, geth_trace)?; - block_access_trace.extend(tx_access_trace); - } - - Ok(AccessSet::from(block_access_trace)) + get_state_accesses(eth_block, geth_traces) } /// Step 3. Query geth for all accounts, storage keys, and codes from @@ -365,32 +558,10 @@ impl BuilderClient

{ /// Step 4. Build a partial StateDB from step 3 pub fn build_state_code_db( - &self, proofs: Vec, codes: HashMap>, ) -> (StateDB, CodeDB) { - let mut sdb = StateDB::new(); - for proof in proofs { - let mut storage = HashMap::new(); - for storage_proof in proof.storage_proof { - storage.insert(storage_proof.key, storage_proof.value); - } - sdb.set_account( - &proof.address, - state_db::Account { - nonce: proof.nonce, - balance: proof.balance, - storage, - code_hash: proof.code_hash, - }, - ) - } - - let mut code_db = CodeDB::new(); - for (_address, code) in codes { - code_db.insert(code.clone()); - } - (sdb, code_db) + build_state_code_db(proofs, codes) } /// Step 5. For each step in TxExecTraces, gen the associated ops and state @@ -401,8 +572,16 @@ impl BuilderClient

{ code_db: CodeDB, eth_block: &EthBlock, geth_traces: &[eth_types::GethExecTrace], + history_hashes: Vec, + prev_state_root: Word, ) -> Result { - let block = Block::new(self.chain_id, self.history_hashes.clone(), eth_block)?; + let block = Block::new( + self.chain_id, + history_hashes, + prev_state_root, + eth_block, + self.circuits_params, + )?; let mut builder = CircuitInputBuilder::new(sdb, code_db, block); builder.handle_block(eth_block, geth_traces)?; Ok(builder) @@ -419,11 +598,19 @@ impl BuilderClient

{ ), Error, > { - let (eth_block, geth_traces) = self.get_block(block_num).await?; - let access_set = self.get_state_accesses(ð_block, &geth_traces)?; + let (eth_block, geth_traces, history_hashes, prev_state_root) = + self.get_block(block_num).await?; + let access_set = Self::get_state_accesses(ð_block, &geth_traces)?; let (proofs, codes) = self.get_state(block_num, access_set).await?; - let (state_db, code_db) = self.build_state_code_db(proofs, codes); - let builder = self.gen_inputs_from_state(state_db, code_db, ð_block, &geth_traces)?; + let (state_db, code_db) = Self::build_state_code_db(proofs, codes); + let builder = self.gen_inputs_from_state( + state_db, + code_db, + ð_block, + &geth_traces, + history_hashes, + prev_state_root, + )?; Ok((builder, eth_block)) } } diff --git a/bus-mapping/src/circuit_input_builder/access.rs b/bus-mapping/src/circuit_input_builder/access.rs index 272eac3acf..1626d6f97a 100644 --- a/bus-mapping/src/circuit_input_builder/access.rs +++ b/bus-mapping/src/circuit_input_builder/access.rs @@ -3,6 +3,9 @@ use eth_types::{evm_types::OpcodeId, Address, GethExecStep, GethExecTrace, ToAdd use ethers_core::utils::get_contract_address; use std::collections::{hash_map::Entry, HashMap, HashSet}; +use AccessValue::{Account, Code, Storage}; +use RW::{READ, WRITE}; + /// State and Code Access with "keys/index" used in the access operation. #[derive(Debug, PartialEq, Eq)] pub enum AccessValue { @@ -92,7 +95,7 @@ impl From> for AccessSet { } /// Source of the code in the EVM execution. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CodeSource { /// Code comes from a deployed contract at `Address`. Address(Address), @@ -116,9 +119,6 @@ pub fn gen_state_access_trace( tx: ð_types::Transaction, geth_trace: &GethExecTrace, ) -> Result, Error> { - use AccessValue::{Account, Code, Storage}; - use RW::{READ, WRITE}; - let mut call_stack: Vec<(Address, CodeSource)> = Vec::new(); let mut accs = vec![Access::new(None, WRITE, Account { address: tx.from })]; if let Some(to) = tx.to { @@ -145,122 +145,129 @@ pub fn gen_state_access_trace( pop_call_stack = step.depth - 1 == next_step.depth; } - match step.op { - OpcodeId::SSTORE => { - let address = contract_address; - let key = step.stack.nth_last(0)?; - accs.push(Access::new(i, WRITE, Storage { address, key })); - } - OpcodeId::SLOAD => { - let address = contract_address; - let key = step.stack.nth_last(0)?; - accs.push(Access::new(i, READ, Storage { address, key })); - } - OpcodeId::SELFBALANCE => { - let address = contract_address; - accs.push(Access::new(i, READ, Account { address })); - } - OpcodeId::CODESIZE => { - if let CodeSource::Address(address) = code_source { + let result: Result<(), Error> = (|| { + match step.op { + OpcodeId::SSTORE => { + let address = contract_address; + let key = step.stack.nth_last(0)?; + accs.push(Access::new(i, WRITE, Storage { address, key })); + } + OpcodeId::SLOAD => { + let address = contract_address; + let key = step.stack.nth_last(0)?; + accs.push(Access::new(i, READ, Storage { address, key })); + } + OpcodeId::SELFBALANCE => { + let address = contract_address; + accs.push(Access::new(i, READ, Account { address })); + } + OpcodeId::CODESIZE => { + if let CodeSource::Address(address) = code_source { + accs.push(Access::new(i, READ, Code { address })); + } + } + OpcodeId::CODECOPY => { + if let CodeSource::Address(address) = code_source { + accs.push(Access::new(i, READ, Code { address })); + } + } + OpcodeId::BALANCE => { + let address = step.stack.nth_last(0)?.to_address(); + accs.push(Access::new(i, READ, Account { address })); + } + OpcodeId::EXTCODEHASH => { + let address = step.stack.nth_last(0)?.to_address(); + accs.push(Access::new(i, READ, Account { address })); + } + OpcodeId::EXTCODESIZE => { + let address = step.stack.nth_last(0)?.to_address(); accs.push(Access::new(i, READ, Code { address })); } - } - OpcodeId::CODECOPY => { - if let CodeSource::Address(address) = code_source { + OpcodeId::EXTCODECOPY => { + let address = step.stack.nth_last(0)?.to_address(); accs.push(Access::new(i, READ, Code { address })); } - } - OpcodeId::BALANCE => { - let address = step.stack.nth_last(0)?.to_address(); - accs.push(Access::new(i, READ, Account { address })); - } - OpcodeId::EXTCODEHASH => { - let address = step.stack.nth_last(0)?.to_address(); - accs.push(Access::new(i, READ, Account { address })); - } - OpcodeId::EXTCODESIZE => { - let address = step.stack.nth_last(0)?.to_address(); - accs.push(Access::new(i, READ, Code { address })); - } - OpcodeId::EXTCODECOPY => { - let address = step.stack.nth_last(0)?.to_address(); - accs.push(Access::new(i, READ, Code { address })); - } - OpcodeId::SELFDESTRUCT => { - let address = contract_address; - accs.push(Access::new(i, WRITE, Account { address })); - let address = step.stack.nth_last(0)?.to_address(); - accs.push(Access::new(i, WRITE, Account { address })); - } - OpcodeId::CREATE => { - if push_call_stack { - // Find CREATE result - let address = get_call_result(&geth_trace.struct_logs[index..]) - .unwrap_or_else(Word::zero) - .to_address(); - if !address.is_zero() { - accs.push(Access::new(i, WRITE, Account { address })); - accs.push(Access::new(i, WRITE, Code { address })); + OpcodeId::SELFDESTRUCT => { + let address = contract_address; + accs.push(Access::new(i, WRITE, Account { address })); + let address = step.stack.nth_last(0)?.to_address(); + accs.push(Access::new(i, WRITE, Account { address })); + } + OpcodeId::CREATE => { + if push_call_stack { + // Find CREATE result + let address = get_call_result(&geth_trace.struct_logs[index..]) + .unwrap_or_else(Word::zero) + .to_address(); + if !address.is_zero() { + accs.push(Access::new(i, WRITE, Account { address })); + accs.push(Access::new(i, WRITE, Code { address })); + } + call_stack.push((address, CodeSource::Address(address))); } - call_stack.push((address, CodeSource::Address(address))); } - } - OpcodeId::CREATE2 => { - if push_call_stack { - // Find CREATE2 result - let address = get_call_result(&geth_trace.struct_logs[index..]) - .unwrap_or_else(Word::zero) - .to_address(); - if !address.is_zero() { - accs.push(Access::new(i, WRITE, Account { address })); - accs.push(Access::new(i, WRITE, Code { address })); + OpcodeId::CREATE2 => { + if push_call_stack { + // Find CREATE2 result + let address = get_call_result(&geth_trace.struct_logs[index..]) + .unwrap_or_else(Word::zero) + .to_address(); + if !address.is_zero() { + accs.push(Access::new(i, WRITE, Account { address })); + accs.push(Access::new(i, WRITE, Code { address })); + } + call_stack.push((address, CodeSource::Address(address))); } - call_stack.push((address, CodeSource::Address(address))); } - } - OpcodeId::CALL => { - let address = contract_address; - accs.push(Access::new(i, WRITE, Account { address })); + OpcodeId::CALL => { + let address = contract_address; + accs.push(Access::new(i, WRITE, Account { address })); - let address = step.stack.nth_last(1)?.to_address(); - accs.push(Access::new(i, WRITE, Account { address })); - accs.push(Access::new(i, READ, Code { address })); - if push_call_stack { - call_stack.push((address, CodeSource::Address(address))); + let address = step.stack.nth_last(1)?.to_address(); + accs.push(Access::new(i, WRITE, Account { address })); + accs.push(Access::new(i, READ, Code { address })); + if push_call_stack { + call_stack.push((address, CodeSource::Address(address))); + } } - } - OpcodeId::CALLCODE => { - let address = contract_address; - accs.push(Access::new(i, WRITE, Account { address })); + OpcodeId::CALLCODE => { + let address = contract_address; + accs.push(Access::new(i, WRITE, Account { address })); - let address = step.stack.nth_last(1)?.to_address(); - accs.push(Access::new(i, WRITE, Account { address })); - accs.push(Access::new(i, READ, Code { address })); - if push_call_stack { - call_stack.push((address, CodeSource::Address(address))); + let address = step.stack.nth_last(1)?.to_address(); + accs.push(Access::new(i, WRITE, Account { address })); + accs.push(Access::new(i, READ, Code { address })); + if push_call_stack { + call_stack.push((address, CodeSource::Address(address))); + } } - } - OpcodeId::DELEGATECALL => { - let address = step.stack.nth_last(1)?.to_address(); - accs.push(Access::new(i, READ, Code { address })); - if push_call_stack { - call_stack.push((contract_address, CodeSource::Address(address))); + OpcodeId::DELEGATECALL => { + let address = step.stack.nth_last(1)?.to_address(); + accs.push(Access::new(i, READ, Code { address })); + if push_call_stack { + call_stack.push((contract_address, CodeSource::Address(address))); + } } - } - OpcodeId::STATICCALL => { - let address = step.stack.nth_last(1)?.to_address(); - accs.push(Access::new(i, READ, Code { address })); - if push_call_stack { - call_stack.push((address, CodeSource::Address(address))); + OpcodeId::STATICCALL => { + let address = step.stack.nth_last(1)?.to_address(); + accs.push(Access::new(i, READ, Code { address })); + if push_call_stack { + call_stack.push((address, CodeSource::Address(address))); + } } + _ => {} } - _ => {} + Ok(()) + })(); + if let Err(e) = result { + log::warn!("err when parsing access: {:?}, step {:?}", e, step); } + if pop_call_stack { if call_stack.len() == 1 { return Err(Error::InvalidGethExecStep( "gen_state_access_trace: call stack will be empty", - step.clone(), + Box::new(step.clone()), )); } call_stack.pop().expect("call stack is empty"); diff --git a/bus-mapping/src/circuit_input_builder/block.rs b/bus-mapping/src/circuit_input_builder/block.rs index d63ceb1480..650c7344bc 100644 --- a/bus-mapping/src/circuit_input_builder/block.rs +++ b/bus-mapping/src/circuit_input_builder/block.rs @@ -1,11 +1,13 @@ //! Block-related utility module -use super::{transaction::Transaction, CopyEvent}; +use super::{ + execution::ExecState, transaction::Transaction, CircuitsParams, CopyEvent, ExecStep, ExpEvent, +}; use crate::{ operation::{OperationContainer, RWCounter}, Error, }; -use eth_types::{Address, Hash, Word}; +use eth_types::{evm_unimplemented, Address, Word}; use std::collections::HashMap; /// Context of a [`Block`] which can mutate in a [`Transaction`]. @@ -39,6 +41,17 @@ impl BlockContext { } } +/// Block-wise execution steps that don't belong to any Transaction. +#[derive(Debug)] +pub struct BlockSteps { + /// EndBlock step that is repeated after the last transaction and before + /// reaching the last EVM row. + pub end_block_not_last: ExecStep, + /// Last EndBlock step that appears in the last EVM row. + pub end_block_last: ExecStep, +} + +// TODO: Remove fields that are duplicated in`eth_block` /// Circuit Input related to a block. #[derive(Debug)] pub struct Block { @@ -59,27 +72,38 @@ pub struct Block { pub difficulty: Word, /// base fee pub base_fee: Word, + /// State root of the previous block + pub prev_state_root: Word, /// Container of operations done in this block. pub container: OperationContainer, /// Transactions contained in the block pub txs: Vec, + /// Block-wise steps + pub block_steps: BlockSteps, /// Copy events in this block. pub copy_events: Vec, /// Inputs to the SHA3 opcode pub sha3_inputs: Vec>, - code: HashMap>, + /// Exponentiation events in the block. + pub exp_events: Vec, + /// Circuits Setup Paramteres + pub circuits_params: CircuitsParams, + /// Original block from geth + pub eth_block: eth_types::Block, } impl Block { /// Create a new block. - pub fn new( + pub fn new( chain_id: Word, history_hashes: Vec, - eth_block: ð_types::Block, + prev_state_root: Word, + eth_block: ð_types::Block, + circuits_params: CircuitsParams, ) -> Result { if eth_block.base_fee_per_gas.is_none() { // FIXME: resolve this once we have proper EIP-1559 support - log::warn!( + evm_unimplemented!( "This does not look like a EIP-1559 block - base_fee_per_gas defaults to zero" ); } @@ -99,11 +123,24 @@ impl Block { timestamp: eth_block.timestamp, difficulty: eth_block.difficulty, base_fee: eth_block.base_fee_per_gas.unwrap_or_default(), + prev_state_root, container: OperationContainer::new(), txs: Vec::new(), + block_steps: BlockSteps { + end_block_not_last: ExecStep { + exec_state: ExecState::EndBlock, + ..ExecStep::default() + }, + end_block_last: ExecStep { + exec_state: ExecState::EndBlock, + ..ExecStep::default() + }, + }, copy_events: Vec::new(), - code: HashMap::new(), + exp_events: Vec::new(), sha3_inputs: Vec::new(), + circuits_params, + eth_block: eth_block.clone(), }) } @@ -120,7 +157,11 @@ impl Block { impl Block { /// Push a copy event to the block. - pub fn add_copy_event(&mut self, copy: CopyEvent) { - self.copy_events.push(copy); + pub fn add_copy_event(&mut self, event: CopyEvent) { + self.copy_events.push(event); + } + /// Push an exponentiation event to the block. + pub fn add_exp_event(&mut self, event: ExpEvent) { + self.exp_events.push(event); } } diff --git a/bus-mapping/src/circuit_input_builder/call.rs b/bus-mapping/src/circuit_input_builder/call.rs index cd616765a7..39a484ea14 100644 --- a/bus-mapping/src/circuit_input_builder/call.rs +++ b/bus-mapping/src/circuit_input_builder/call.rs @@ -1,7 +1,9 @@ use super::CodeSource; use crate::{exec_trace::OperationRef, Error}; -use eth_types::evm_types::Memory; -use eth_types::{evm_types::OpcodeId, Address, Hash, Word}; +use eth_types::{ + evm_types::{Memory, OpcodeId}, + Address, Hash, Word, +}; /// Type of a *CALL*/CREATE* Function. #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -49,12 +51,14 @@ impl TryFrom for CallKind { } /// Circuit Input related to an Ethereum Call -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct Call { /// Unique call identifier within the Block. pub call_id: usize, /// Caller's id. pub caller_id: usize, + /// Last Callee's id. + pub last_callee_id: usize, /// Type of call pub kind: CallKind, /// This call is being executed without write access (STATIC) @@ -87,6 +91,10 @@ pub struct Call { pub return_data_offset: u64, /// Return data length pub return_data_length: u64, + /// last callee's return data offset + pub last_callee_return_data_offset: u64, + /// last callee's return data length + pub last_callee_return_data_length: u64, } impl Call { @@ -95,6 +103,23 @@ impl Call { pub fn is_create(&self) -> bool { self.kind.is_create() } + + /// This call is call with op DELEGATECALL + pub fn is_delegatecall(&self) -> bool { + matches!(self.kind, CallKind::DelegateCall) + } + + /// Get the code address if possible + pub fn code_address(&self) -> Option

{ + match self.kind { + CallKind::Call | CallKind::StaticCall => Some(self.address), + CallKind::CallCode | CallKind::DelegateCall => match self.code_source { + CodeSource::Address(address) => Some(address), + _ => None, + }, + CallKind::Create | CallKind::Create2 => None, + } + } } /// Context of a [`Call`]. diff --git a/bus-mapping/src/circuit_input_builder/execution.rs b/bus-mapping/src/circuit_input_builder/execution.rs index 8172715349..20b3048682 100644 --- a/bus-mapping/src/circuit_input_builder/execution.rs +++ b/bus-mapping/src/circuit_input_builder/execution.rs @@ -6,14 +6,14 @@ use crate::{ }; use eth_types::{ evm_types::{Gas, GasCost, OpcodeId, ProgramCounter}, - GethExecStep, H256, + GethExecStep, Word, H256, }; use gadgets::impl_expr; use halo2_proofs::plonk::Expression; use strum_macros::EnumIter; /// An execution step of the EVM. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct ExecStep { /// Execution state pub exec_state: ExecState, @@ -36,12 +36,17 @@ pub struct ExecStep { /// The global counter when this step was executed. pub rwc: RWCounter, /// Reversible Write Counter. Counter of write operations in the call that - /// will need to be undone in case of a revert. + /// will need to be undone in case of a revert. Value at the beginning of + /// the step. pub reversible_write_counter: usize, + /// Number of reversible write operations done by this step. + pub reversible_write_counter_delta: usize, /// Log index when this step was executed. pub log_id: usize, /// The list of references to Operations in the container pub bus_mapping_instance: Vec, + /// Number of rw operations performed via a copy event in this step. + pub copy_rw_counter_delta: u64, /// Error generated by this step pub error: Option, } @@ -66,8 +71,10 @@ impl ExecStep { call_index: call_ctx.index, rwc, reversible_write_counter, + reversible_write_counter_delta: 0, log_id, bus_mapping_instance: Vec::new(), + copy_rw_counter_delta: 0, error: None, } } @@ -79,26 +86,45 @@ impl ExecStep { Some(ExecError::OutOfGas(_) | ExecError::StackOverflow | ExecError::StackUnderflow) ) } -} -impl Default for ExecStep { - fn default() -> Self { - Self { - exec_state: ExecState::Op(OpcodeId::INVALID(0)), - pc: ProgramCounter(0), - stack_size: 0, - memory_size: 0, - gas_left: Gas(0), - gas_cost: GasCost(0), - gas_refund: Gas(0), - call_index: 0, - rwc: RWCounter(0), - reversible_write_counter: 0, - log_id: 0, - bus_mapping_instance: Vec::new(), - error: None, + /// Try get opcode, if possible + pub fn opcode(&self) -> Option { + match self.exec_state { + ExecState::Op(op) => Some(op), + _ => None, } } + + /// get rw index + pub fn rw_index(&self, index: usize) -> OperationRef { + self.bus_mapping_instance[index] + } + + /// Get the size of read and writes + pub fn rw_indices_len(&self) -> usize { + self.bus_mapping_instance.len() + } + + /// Get stack pointer + pub fn stack_pointer(&self) -> u64 { + 1024 - self.stack_size as u64 + } + + /// The memory size in word **before** this step + pub fn memory_word_size(&self) -> u64 { + let n_bytes_word = 32u64; + let memory_size = self.memory_size as u64; + // EVM always pads the memory size to word size + // https://github.com/ethereum/go-ethereum/blob/a340721aa909ea4b541ffd1ea5e9c7bd441ff769/core/vm/interpreter.go#L201-L205 + // Thus, the memory size must be a multiple of 32 bytes. + assert_eq!(memory_size % n_bytes_word, 0); + memory_size / n_bytes_word + } + + /// Get program counter + pub fn program_counter(&self) -> u64 { + self.pc.0.try_into().expect("program counter can fit u64") + } } /// Execution state @@ -110,6 +136,14 @@ pub enum ExecState { BeginTx, /// Virtual step End Tx EndTx, + /// Virtual step End Block + EndBlock, +} + +impl Default for ExecState { + fn default() -> Self { + ExecState::Op(OpcodeId::STOP) + } } impl ExecState { @@ -153,8 +187,11 @@ impl ExecState { /// Defines the various source/destination types for a copy event. #[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter)] pub enum CopyDataType { + /// When we need to pad the Copy rows of the circuit up to a certain maximum + /// with rows that are not "useful". + Padding = 0, /// When the source for the copy event is the bytecode table. - Bytecode = 1, + Bytecode, /// When the source/destination for the copy event is memory. Memory, /// When the source for the copy event is tx's calldata. @@ -240,6 +277,11 @@ impl CopyEvent { self.rw_counter(self.bytes.len() * 2) - self.rw_counter(step_index) } + /// Number of rw operations performed by this copy event + pub fn rw_counter_delta(&self) -> u64 { + self.rw_counter_increase(self.bytes.len() * 2) + } + // increase in rw counter from the start of the copy event to step index fn rw_counter_increase(&self, step_index: usize) -> u64 { let source_rw_increase = match self.src_type { @@ -250,13 +292,65 @@ impl CopyEvent { .checked_sub(self.src_addr) .unwrap_or_default(), ), - CopyDataType::RlcAcc | CopyDataType::TxLog => unreachable!(), + CopyDataType::RlcAcc | CopyDataType::TxLog | CopyDataType::Padding => unreachable!(), }; let destination_rw_increase = match self.dst_type { CopyDataType::RlcAcc | CopyDataType::Bytecode => 0, CopyDataType::TxLog | CopyDataType::Memory => u64::try_from(step_index).unwrap() / 2, - CopyDataType::TxCalldata => unreachable!(), + CopyDataType::TxCalldata | CopyDataType::Padding => unreachable!(), }; source_rw_increase + destination_rw_increase } } + +/// Intermediary multiplication step, representing `a * b == d (mod 2^256)` +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ExpStep { + /// First multiplicand. + pub a: Word, + /// Second multiplicand. + pub b: Word, + /// Multiplication result. + pub d: Word, +} + +impl From<(Word, Word, Word)> for ExpStep { + fn from(values: (Word, Word, Word)) -> Self { + Self { + a: values.0, + b: values.1, + d: values.2, + } + } +} + +/// Event representating an exponentiation `a ^ b == d (mod 2^256)`. +#[derive(Clone, Debug)] +pub struct ExpEvent { + /// Identifier for the exponentiation trace. + pub identifier: usize, + /// Base `a` for the exponentiation. + pub base: Word, + /// Exponent `b` for the exponentiation. + pub exponent: Word, + /// Exponentiation result. + pub exponentiation: Word, + /// Intermediate multiplication results. + pub steps: Vec, +} + +impl Default for ExpEvent { + fn default() -> Self { + Self { + identifier: 0, + base: 2.into(), + exponent: 2.into(), + exponentiation: 4.into(), + steps: vec![ExpStep { + a: 2.into(), + b: 2.into(), + d: 4.into(), + }], + } + } +} diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index 887001b947..9f5b94c9df 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -2,10 +2,14 @@ use super::{ get_call_memory_offset_length, get_create_init_code, Block, BlockContext, Call, CallContext, - CallKind, CodeSource, CopyEvent, ExecState, ExecStep, Transaction, TransactionContext, + CallKind, CodeSource, CopyEvent, ExecState, ExecStep, ExpEvent, Transaction, + TransactionContext, }; use crate::{ - error::{get_step_reported_error, ExecError}, + error::{ + get_step_reported_error, DepthError, ExecError, InsufficientBalanceError, + NonceUintOverflowError, + }, exec_trace::OperationRef, operation::{ AccountField, AccountOp, CallContextField, CallContextOp, MemoryOp, Op, OpEnum, Operation, @@ -19,7 +23,7 @@ use eth_types::{ evm_types::{ gas_utils::memory_expansion_gas_cost, Gas, GasCost, MemoryAddress, OpcodeId, StackAddress, }, - Address, GethExecStep, ToAddress, ToBigEndian, ToWord, Word, H256, + Address, Bytecode, GethExecStep, ToAddress, ToBigEndian, ToWord, Word, H256, U256, }; use ethers_core::utils::{get_contract_address, get_create2_address}; use std::cmp::max; @@ -59,7 +63,7 @@ impl<'a> CircuitInputStateRef<'a> { pub fn new_begin_tx_step(&self) -> ExecStep { ExecStep { exec_state: ExecState::BeginTx, - gas_left: Gas(self.tx.gas), + gas_left: Gas(self.tx.gas()), rwc: self.block_ctx.rwc, ..Default::default() } @@ -99,6 +103,9 @@ impl<'a> CircuitInputStateRef<'a> { /// bus-mapping instance of the current [`ExecStep`]. Then increase the /// block_ctx [`RWCounter`](crate::operation::RWCounter) by one. pub fn push_op(&mut self, step: &mut ExecStep, rw: RW, op: T) { + if let OpEnum::Account(op) = op.clone().into_enum() { + self.check_update_sdb_account(rw, &op) + } let op_ref = self.block .container @@ -161,24 +168,18 @@ impl<'a> CircuitInputStateRef<'a> { /// This method should be used in `Opcode::gen_associated_ops` instead of /// `push_op` when the operation is `RW::WRITE` and it can be reverted (for /// example, a write [`StorageOp`](crate::operation::StorageOp)). - pub fn push_op_reversible( - &mut self, - step: &mut ExecStep, - rw: RW, - op: T, - ) -> Result<(), Error> { - if matches!(rw, RW::WRITE) { - self.apply_op(&op.clone().into_enum()); - } + pub fn push_op_reversible(&mut self, step: &mut ExecStep, op: T) -> Result<(), Error> { + self.check_apply_op(&op.clone().into_enum()); let op_ref = self.block.container.insert(Operation::new_reversible( self.block_ctx.rwc.inc_pre(), - rw, + RW::WRITE, op, )); step.bus_mapping_instance.push(op_ref); // Increase reversible_write_counter self.call_ctx_mut()?.reversible_write_counter += 1; + step.reversible_write_counter_delta += 1; // Add the operation into reversible_ops if this call is not persistent if !self.call()?.is_persistent { @@ -261,6 +262,72 @@ impl<'a> CircuitInputStateRef<'a> { Ok(()) } + /// First check the validity and consistency of the rw operation against the + /// account in the StateDB, then if the rw operation is a write, apply + /// it to the corresponding account in the StateDB. + fn check_update_sdb_account(&mut self, rw: RW, op: &AccountOp) { + let account = self.sdb.get_account_mut(&op.address).1; + // -- sanity check begin -- + // Verify that a READ doesn't change the field value + if matches!(rw, RW::READ) && op.value_prev != op.value { + panic!( + "RWTable Account field read where value_prev != value rwc: {}, op: {:?}", + self.block_ctx.rwc.0, op + ) + } + // NOTE: In the State Circuit we use code_hash=0 to encode non-existing + // accounts, but the corresponding account in the state DB is empty + // (which means code_hash=EMPTY_HASH). + let account_value_prev = match op.field { + AccountField::Nonce => account.nonce.to_word(), + AccountField::Balance => account.balance, + AccountField::CodeHash => { + if account.is_empty() { + if op.value.is_zero() { + // Writing code_hash=0 to empty account is a noop to the StateDB. + return; + } + // Reading a code_hash=EMPTY_HASH of an empty account in the StateDB is encoded + // as code_hash=0 (non-existing account encoding) in the State Circuit. + Word::zero() + } else { + account.code_hash.to_word() + } + } + }; + + // Verify that the previous value matches the account field value in the StateDB + if op.value_prev != account_value_prev { + panic!( + "RWTable Account field {:?} lookup doesn't match account value + account: {:?}, rwc: {}, op: {:?}", + rw, account, self.block_ctx.rwc.0, op + ); + } + // Verify that no read is done to a field other than CodeHash to a non-existing + // account (only CodeHash reads with value=0 can be done to non-existing + // accounts, which the State Circuit translates to MPT + // AccountNonExisting proofs lookups). + if (!matches!(op.field, AccountField::CodeHash) + && (matches!(rw, RW::READ) || (op.value_prev.is_zero() && op.value.is_zero()))) + && account.is_empty() + { + panic!( + "RWTable Account field {:?} lookup to non-existing account rwc: {}, op: {:?}", + rw, self.block_ctx.rwc.0, op + ); + } + // -- sanity check end -- + // Perform the write to the account in the StateDB + if matches!(rw, RW::WRITE) { + match op.field { + AccountField::Nonce => account.nonce = op.value.as_u64(), + AccountField::Balance => account.balance = op.value, + AccountField::CodeHash => account.code_hash = H256::from(op.value.to_be_bytes()), + } + } + } + /// Push a read type [`AccountOp`] into the /// [`OperationContainer`](crate::operation::OperationContainer) with the /// next [`RWCounter`](crate::operation::RWCounter), and then @@ -273,14 +340,9 @@ impl<'a> CircuitInputStateRef<'a> { address: Address, field: AccountField, value: Word, - value_prev: Word, - ) -> Result<(), Error> { - self.push_op( - step, - RW::READ, - AccountOp::new(address, field, value, value_prev), - ); - Ok(()) + ) { + let op = AccountOp::new(address, field, value, value); + self.push_op(step, RW::READ, op); } /// Push a write type [`AccountOp`] into the @@ -297,11 +359,8 @@ impl<'a> CircuitInputStateRef<'a> { value: Word, value_prev: Word, ) -> Result<(), Error> { - self.push_op( - step, - RW::WRITE, - AccountOp::new(address, field, value, value_prev), - ); + let op = AccountOp::new(address, field, value, value_prev); + self.push_op(step, RW::WRITE, op); Ok(()) } @@ -406,24 +465,77 @@ impl<'a> CircuitInputStateRef<'a> { } /// Push 2 reversible [`AccountOp`] to update `sender` and `receiver`'s - /// balance by `value`, with `sender` being extraly charged with `fee`. + /// balance by `value`. If `fee` is existing (not None), also need to push 1 + /// non-reversible [`AccountOp`] to update `sender` balance by `fee`. + #[allow(clippy::too_many_arguments)] pub fn transfer_with_fee( &mut self, step: &mut ExecStep, sender: Address, receiver: Address, + receiver_exists: bool, + must_create: bool, value: Word, - fee: Word, + fee: Option, ) -> Result<(), Error> { let (found, sender_account) = self.sdb.get_account(&sender); if !found { return Err(Error::AccountNotFound(sender)); } - let sender_balance_prev = sender_account.balance; - let sender_balance = sender_account.balance - value - fee; + let mut sender_balance_prev = sender_account.balance; + debug_assert!( + sender_account.balance >= value + fee.unwrap_or_default(), + "invalid amount balance {:?} value {:?} fee {:?}", + sender_balance_prev, + value, + fee + ); + if let Some(fee) = fee { + let sender_balance = sender_balance_prev - fee; + log::trace!( + "sender balance update with fee (not reversible): {:?} {:?}->{:?}", + sender, + sender_balance_prev, + sender_balance + ); + self.push_op( + step, + RW::WRITE, + AccountOp { + address: sender, + field: AccountField::Balance, + value: sender_balance, + value_prev: sender_balance_prev, + }, + ); + sender_balance_prev = sender_balance; + } + let sender_balance = sender_balance_prev - value; + log::trace!( + "sender balance update with value: {:?} {:?}->{:?}", + sender, + sender_balance_prev, + sender_balance + ); + // If receiver doesn't exist, create it + if (!receiver_exists && !value.is_zero()) || must_create { + self.push_op_reversible( + step, + AccountOp { + address: receiver, + field: AccountField::CodeHash, + value: CodeDB::empty_code_hash().to_word(), + value_prev: Word::zero(), + }, + )?; + } + if value.is_zero() { + // Skip transfer if value == 0 + return Ok(()); + } + self.push_op_reversible( step, - RW::WRITE, AccountOp { address: sender, field: AccountField::Balance, @@ -437,7 +549,6 @@ impl<'a> CircuitInputStateRef<'a> { let receiver_balance = receiver_account.balance + value; self.push_op_reversible( step, - RW::WRITE, AccountOp { address: receiver, field: AccountField::Balance, @@ -455,9 +566,19 @@ impl<'a> CircuitInputStateRef<'a> { step: &mut ExecStep, sender: Address, receiver: Address, + receiver_exists: bool, + must_create: bool, value: Word, ) -> Result<(), Error> { - self.transfer_with_fee(step, sender, receiver, value, Word::zero()) + self.transfer_with_fee( + step, + sender, + receiver, + receiver_exists, + must_create, + value, + None, + ) } /// Fetch and return code for the given code hash from the code DB. @@ -476,6 +597,13 @@ impl<'a> CircuitInputStateRef<'a> { .map(|caller_idx| &self.tx.calls()[caller_idx]) } + /// Mutable reference to the current call's caller Call + pub fn caller_mut(&mut self) -> Result<&mut Call, Error> { + self.tx_ctx + .caller_index() + .map(|caller_idx| &mut self.tx.calls_mut()[caller_idx]) + } + /// Reference to the current Call pub fn call(&self) -> Result<&Call, Error> { self.tx_ctx @@ -568,7 +696,6 @@ impl<'a> CircuitInputStateRef<'a> { address.0[0..19] == [0u8; 19] && (1..=9).contains(&address.0[19]) } - // TODO: Remove unwrap() and add err handling. /// Parse [`Call`] from a *CALL*/CREATE* step. pub fn parse_call(&mut self, step: &GethExecStep) -> Result { let is_success = *self @@ -587,7 +714,7 @@ impl<'a> CircuitInputStateRef<'a> { step.stack.nth_last(2)?, ), CallKind::CallCode => (caller.address, caller.address, step.stack.nth_last(2)?), - CallKind::DelegateCall => (caller.caller_address, caller.address, Word::zero()), + CallKind::DelegateCall => (caller.caller_address, caller.address, caller.value), CallKind::StaticCall => ( caller.address, step.stack.nth_last(1)?.to_address(), @@ -641,6 +768,7 @@ impl<'a> CircuitInputStateRef<'a> { let call = Call { call_id: self.block_ctx.rwc.0, caller_id: caller.call_id, + last_callee_id: 0, kind, is_static: kind == CallKind::StaticCall || caller.is_static, is_root: false, @@ -657,6 +785,8 @@ impl<'a> CircuitInputStateRef<'a> { call_data_length, return_data_offset, return_data_length, + last_callee_return_data_offset: 0, + last_callee_return_data_length: 0, }; Ok(call) @@ -706,20 +836,12 @@ impl<'a> CircuitInputStateRef<'a> { None } } - OperationRef(Target::AccountDestructed, idx) => { - let operation = &self.block.container.account_destructed[*idx]; - if operation.rw().is_write() && operation.reversible() { - Some(OpEnum::AccountDestructed(operation.op().reverse())) - } else { - None - } - } _ => None, } } - /// Apply op to state. - fn apply_op(&mut self, op: &OpEnum) { + /// Check and apply op to state. + fn check_apply_op(&mut self, op: &OpEnum) { match &op { OpEnum::Storage(op) => { self.sdb.set_storage(&op.address, &op.key, &op.value); @@ -742,20 +864,10 @@ impl<'a> CircuitInputStateRef<'a> { .remove_account_storage_from_access_list(&(op.address, op.key)); } } - OpEnum::Account(op) => { - let (_, account) = self.sdb.get_account_mut(&op.address); - match op.field { - AccountField::Nonce => account.nonce = op.value, - AccountField::Balance => account.balance = op.value, - AccountField::CodeHash => { - account.code_hash = op.value.to_be_bytes().into(); - } - } - } + OpEnum::Account(op) => self.check_update_sdb_account(RW::WRITE, op), OpEnum::TxRefund(op) => { self.sdb.set_refund(op.value); } - OpEnum::AccountDestructed(_) => unimplemented!(), _ => unreachable!(), }; } @@ -771,7 +883,7 @@ impl<'a> CircuitInputStateRef<'a> { // Apply reversions for (step_index, op_ref) in reversion_group.op_refs.iter().rev().copied() { if let Some(op) = self.get_rev_op_by_ref(&op_ref) { - self.apply_op(&op); + self.check_apply_op(&op); let rev_op_ref = self.block.container.insert_op_enum( self.block_ctx.rwc.inc_pre(), RW::WRITE, @@ -792,14 +904,56 @@ impl<'a> CircuitInputStateRef<'a> { } } - /// Handle a return step caused by any opcode that causes a return to the + /// Handle a restore and a return step caused by any opcode that causes a return to the /// previous call context. - pub fn handle_return(&mut self, step: &GethExecStep) -> Result<(), Error> { + pub fn handle_return( + &mut self, + exec_step: &mut ExecStep, + geth_steps: &[GethExecStep], + need_restore: bool, + ) -> Result<(), Error> { + if need_restore { + self.handle_restore_context(exec_step, geth_steps)?; + } + + let step = &geth_steps[0]; + // handle return_data + let (return_data_offset, return_data_length) = { + if !self.call()?.is_root { + let (offset, length) = match step.op { + OpcodeId::RETURN | OpcodeId::REVERT => { + let offset = step.stack.nth_last(0)?.as_usize(); + let length = step.stack.nth_last(1)?.as_usize(); + // At the moment it conflicts with `call_ctx` and `caller_ctx`. + let callee_memory = self.call_ctx()?.memory.clone(); + let caller_ctx = self.caller_ctx_mut()?; + caller_ctx.return_data.resize(length, 0); + if length != 0 { + caller_ctx.return_data[0..length] + .copy_from_slice(&callee_memory.0[offset..offset + length]); + } + (offset, length) + } + _ => { + let caller_ctx = self.caller_ctx_mut()?; + caller_ctx.return_data.truncate(0); + (0, 0) + } + }; + + (offset.try_into().unwrap(), length.try_into().unwrap()) + } else { + (0, 0) + } + }; + let call = self.call()?.clone(); let call_ctx = self.call_ctx()?; + let call_success_create: bool = + call.is_create() && call.is_success && step.op == OpcodeId::RETURN; // Store deployed code if it's a successful create - if call.is_create() && call.is_success && step.op == OpcodeId::RETURN { + if call_success_create { let offset = step.stack.nth_last(0)?; let length = step.stack.nth_last(1)?; let code = call_ctx @@ -818,21 +972,73 @@ impl<'a> CircuitInputStateRef<'a> { self.handle_reversion(); } + // If current call has caller. + if let Ok(caller) = self.caller_mut() { + caller.last_callee_id = call.call_id; + // EIP-211 CREATE/CREATE2 call successful case should set RETURNDATASIZE = 0 + if call_success_create { + caller.last_callee_return_data_length = 0u64; + caller.last_callee_return_data_offset = 0u64; + } else { + caller.last_callee_return_data_length = return_data_length; + caller.last_callee_return_data_offset = return_data_offset; + } + } + + // If current call has caller_ctx (has caller) + if let Ok(caller_ctx) = self.caller_ctx_mut() { + // EIP-211 CREATE/CREATE2 call successful case should set RETURNDATASIZE = 0 + if call_success_create { + caller_ctx.return_data.truncate(0); + } + } + self.tx_ctx.pop_call_ctx(); Ok(()) } /// Bus mapping for the RestoreContextGadget as used in RETURN. - // TODO: unify this with restore context bus mapping for STOP. - // TODO: unify this with the `handle return function above.` pub fn handle_restore_context( &mut self, - steps: &[GethExecStep], exec_step: &mut ExecStep, + steps: &[GethExecStep], ) -> Result<(), Error> { let call = self.call()?.clone(); + let geth_step = steps + .get(0) + .ok_or(Error::InternalError("invalid index 0"))?; + let is_return_revert = geth_step.op == OpcodeId::REVERT || geth_step.op == OpcodeId::RETURN; + + if !is_return_revert && !call.is_success { + // add call failure ops for exception cases + self.call_context_read( + exec_step, + call.call_id, + CallContextField::IsSuccess, + 0u64.into(), + ); + + // Even call.rw_counter_end_of_reversion is zero for now, it will set in + // set_value_ops_call_context_rwc_eor later + // if call fails, no matter root or internal, read RwCounterEndOfReversion for + // circuit constraint. + self.call_context_read( + exec_step, + call.call_id, + CallContextField::RwCounterEndOfReversion, + call.rw_counter_end_of_reversion.into(), + ); + + if call.is_root { + return Ok(()); + } + } + let caller = self.caller()?.clone(); + let geth_step_next = steps + .get(1) + .ok_or(Error::InternalError("invalid index 1"))?; self.call_context_read( exec_step, call.call_id, @@ -840,9 +1046,6 @@ impl<'a> CircuitInputStateRef<'a> { caller.call_id.into(), ); - let geth_step = &steps[0]; - let geth_step_next = &steps[1]; - let [last_callee_return_data_offset, last_callee_return_data_length] = match geth_step.op { OpcodeId::STOP => [Word::zero(); 2], OpcodeId::REVERT | OpcodeId::RETURN => { @@ -856,7 +1059,7 @@ impl<'a> CircuitInputStateRef<'a> { [offset, length] } } - _ => unreachable!(), + _ => [Word::zero(), Word::zero()], }; let curr_memory_word_size = (exec_step.memory_size as u64) / 32; @@ -872,14 +1075,18 @@ impl<'a> CircuitInputStateRef<'a> { let memory_expansion_gas_cost = memory_expansion_gas_cost(curr_memory_word_size, next_memory_word_size); - let code_deposit_cost = if call.is_create() { + let code_deposit_cost = if call.is_create() && call.is_success { GasCost::CODE_DEPOSIT_BYTE_COST.as_u64() * last_callee_return_data_length.as_u64() } else { 0 }; let gas_refund = geth_step.gas.0 - memory_expansion_gas_cost - code_deposit_cost; - let caller_gas_left = geth_step_next.gas.0 - gas_refund; + let caller_gas_left = if is_return_revert || call.is_success { + geth_step_next.gas.0 - gas_refund + } else { + geth_step_next.gas.0 + }; for (field, value) in [ (CallContextField::IsRoot, (caller.is_root as u64).into()), @@ -906,15 +1113,24 @@ impl<'a> CircuitInputStateRef<'a> { self.call_context_read(exec_step, caller.call_id, field, value); } + // EIP-211: CREATE/CREATE2 call successful case should set RETURNDATASIZE = 0 for (field, value) in [ (CallContextField::LastCalleeId, call.call_id.into()), ( CallContextField::LastCalleeReturnDataOffset, - last_callee_return_data_offset, + if call.is_create() && call.is_success { + U256::zero() + } else { + last_callee_return_data_offset + }, ), ( CallContextField::LastCalleeReturnDataLength, - last_callee_return_data_length, + if call.is_create() && call.is_success { + U256::zero() + } else { + last_callee_return_data_length + }, ), ] { self.call_context_write(exec_step, caller.call_id, field, value); @@ -924,8 +1140,14 @@ impl<'a> CircuitInputStateRef<'a> { } /// Push a copy event to the state. - pub fn push_copy(&mut self, copy: CopyEvent) { - self.block.add_copy_event(copy); + pub fn push_copy(&mut self, step: &mut ExecStep, event: CopyEvent) { + step.copy_rw_counter_delta = event.rw_counter_delta(); + self.block.add_copy_event(event); + } + + /// Push a exponentiation event to the state. + pub fn push_exponentiation(&mut self, event: ExpEvent) { + self.block.add_exp_event(event) } pub(crate) fn get_step_err( @@ -941,14 +1163,27 @@ impl<'a> CircuitInputStateRef<'a> { return Ok(Some(ExecError::InvalidOpcode)); } - // When last step has opcodes that halt, there's no error. - if matches!(next_step, None) - && matches!( + let call = self.call()?; + + if matches!(next_step, None) { + // enumerating call scope successful cases + // case 1: call with normal halt opcode termination + if matches!( step.op, - OpcodeId::STOP | OpcodeId::RETURN | OpcodeId::REVERT | OpcodeId::SELFDESTRUCT - ) - { - return Ok(None); + OpcodeId::STOP | OpcodeId::REVERT | OpcodeId::SELFDESTRUCT + ) { + return Ok(None); + } + // case 2: call is NOT Create (Create represented by empty tx.to) and halt by + // opcode::Return + if !call.is_create() && step.op == OpcodeId::RETURN { + return Ok(None); + } + // case 3 Create with successful RETURN + if call.is_create() && call.is_success && step.op == OpcodeId::RETURN { + return Ok(None); + } + // more other case... } let next_depth = next_step.map(|s| s.depth).unwrap_or(0); @@ -956,8 +1191,13 @@ impl<'a> CircuitInputStateRef<'a> { .map(|s| s.stack.last().unwrap_or_else(|_| Word::zero())) .unwrap_or_else(Word::zero); - let call = self.call()?; let call_ctx = self.call_ctx()?; + // get value first if call/create + let value = match step.op { + OpcodeId::CALL | OpcodeId::CALLCODE => step.stack.nth_last(2)?, + OpcodeId::CREATE | OpcodeId::CREATE2 => step.stack.nth_last(0)?, + _ => Word::zero(), + }; // Return from a call with a failure if step.depth == next_depth + 1 && next_result.is_zero() { @@ -980,17 +1220,21 @@ impl<'a> CircuitInputStateRef<'a> { { Some(ExecError::WriteProtection) } + OpcodeId::CALL if call.is_static && !value.is_zero() => { + Some(ExecError::WriteProtection) + } + OpcodeId::REVERT => None, _ => { return Err(Error::UnexpectedExecStepError( "call failure without return", - step.clone(), + Box::new(step.clone()), )); } }); } else { // Return from a {CREATE, CREATE2} with a failure, via RETURN - if !call.is_root && call.is_create() { + if call.is_create() { let offset = step.stack.nth_last(0)?; let length = step.stack.nth_last(1)?; if length > Word::from(0x6000u64) { @@ -1005,13 +1249,13 @@ impl<'a> CircuitInputStateRef<'a> { } else { return Err(Error::UnexpectedExecStepError( "failure in RETURN from {CREATE, CREATE2}", - step.clone(), + Box::new(step.clone()), )); } } else { return Err(Error::UnexpectedExecStepError( "failure in RETURN", - step.clone(), + Box::new(step.clone()), )); } } @@ -1031,7 +1275,7 @@ impl<'a> CircuitInputStateRef<'a> { { return Err(Error::UnexpectedExecStepError( "success result without {RETURN, STOP, SELFDESTRUCT}", - step.clone(), + Box::new(step.clone()), )); } @@ -1049,19 +1293,14 @@ impl<'a> CircuitInputStateRef<'a> { && next_pc != 0 { if step.depth == 1025 { - return Ok(Some(ExecError::Depth)); - } - - // Insufficient_balance - let value = match step.op { - OpcodeId::CALL | OpcodeId::CALLCODE => step.stack.nth_last(2)?, - OpcodeId::CREATE | OpcodeId::CREATE2 => step.stack.nth_last(0)?, - _ => Word::zero(), - }; - - // CALL with value - if matches!(step.op, OpcodeId::CALL) && !value.is_zero() && self.call()?.is_static { - return Ok(Some(ExecError::WriteProtection)); + return Ok(Some(ExecError::Depth(match step.op { + OpcodeId::CALL | OpcodeId::CALLCODE => DepthError::Call, + OpcodeId::CREATE => DepthError::Create, + OpcodeId::CREATE2 => DepthError::Create2, + op => { + unreachable!("Depth error unexpected for opcode: {:?}", op) + } + }))); } let sender = self.call()?.address; @@ -1070,16 +1309,32 @@ impl<'a> CircuitInputStateRef<'a> { return Err(Error::AccountNotFound(sender)); } if account.balance < value { - return Ok(Some(ExecError::InsufficientBalance)); + return Ok(Some(ExecError::InsufficientBalance(match step.op { + OpcodeId::CALL | OpcodeId::CALLCODE => InsufficientBalanceError::Call, + OpcodeId::CREATE => InsufficientBalanceError::Create, + OpcodeId::CREATE2 => InsufficientBalanceError::Create2, + op => { + unreachable!("insufficient balance error unexpected for opcode: {:?}", op) + } + }))); + } + + // Nonce Uint overflow + // If user's nonce is equal u64::MAX, nonce will be overflow in this call + // Nonce is u64 so it's impossible to larger than u64::MAX, that's why we're using `==` + // here. + if account.nonce == u64::MAX { + return Ok(Some(ExecError::NonceUintOverflow(match step.op { + OpcodeId::CREATE => NonceUintOverflowError::Create, + OpcodeId::CREATE2 => NonceUintOverflowError::Create2, + op => unreachable!("Nonce Uint overflow error unexpected for opcode: {:?}", op), + }))); } // Address collision - if matches!(step.op, OpcodeId::CREATE | OpcodeId::CREATE2) { - let address = match step.op { - OpcodeId::CREATE => self.create_address()?, - OpcodeId::CREATE2 => self.create2_address(step)?, - _ => unreachable!(), - }; + if matches!(step.op, OpcodeId::CREATE2) { + let address = self.create2_address(step)?; + let (found, _) = self.sdb.get_account(&address); if found { return Ok(Some(ExecError::ContractAddressCollision)); @@ -1088,7 +1343,7 @@ impl<'a> CircuitInputStateRef<'a> { return Err(Error::UnexpectedExecStepError( "*CALL*/CREATE* code not executed", - step.clone(), + Box::new(step.clone()), )); } @@ -1122,4 +1377,63 @@ impl<'a> CircuitInputStateRef<'a> { } Ok(()) } + + /// Generate copy steps for bytecode. + pub(crate) fn gen_copy_steps_for_bytecode( + &mut self, + exec_step: &mut ExecStep, + bytecode: &Bytecode, + src_addr: u64, + dst_addr: u64, + src_addr_end: u64, + bytes_left: u64, + ) -> Result, Error> { + let mut copy_steps = Vec::with_capacity(bytes_left as usize); + for idx in 0..bytes_left { + let addr = src_addr.checked_add(idx).unwrap_or(src_addr_end); + let step = if addr < src_addr_end { + let code = bytecode.code.get(addr as usize).unwrap(); + (code.value, code.is_code) + } else { + (0, false) + }; + copy_steps.push(step); + self.memory_write(exec_step, (dst_addr + idx).into(), step.0)?; + } + + Ok(copy_steps) + } + + /// Generate copy steps for call data. + pub(crate) fn gen_copy_steps_for_call_data( + &mut self, + exec_step: &mut ExecStep, + src_addr: u64, + dst_addr: u64, + src_addr_end: u64, + bytes_left: u64, + ) -> Result, Error> { + let mut copy_steps = Vec::with_capacity(bytes_left as usize); + for idx in 0..bytes_left { + let addr = src_addr.checked_add(idx).unwrap_or(src_addr_end); + let value = if addr < src_addr_end { + let byte = + self.call_ctx()?.call_data[(addr - self.call()?.call_data_offset) as usize]; + if !self.call()?.is_root { + self.push_op( + exec_step, + RW::READ, + MemoryOp::new(self.call()?.caller_id, addr.into(), byte), + ); + } + byte + } else { + 0 + }; + copy_steps.push((value, false)); + self.memory_write(exec_step, (dst_addr + idx).into(), value)?; + } + + Ok(copy_steps) + } } diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index 583c990783..ad6d106bf7 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -1,19 +1,24 @@ use super::*; -use crate::circuit_input_builder::access::gen_state_access_trace; -use crate::error::{ExecError, OogError}; -use crate::geth_errors::{ - GETH_ERR_GAS_UINT_OVERFLOW, GETH_ERR_OUT_OF_GAS, GETH_ERR_STACK_OVERFLOW, - GETH_ERR_STACK_UNDERFLOW, +use crate::{ + circuit_input_builder::access::gen_state_access_trace, + error::{DepthError, ExecError, InsufficientBalanceError, OogError}, + geth_errors::{ + GETH_ERR_GAS_UINT_OVERFLOW, GETH_ERR_OUT_OF_GAS, GETH_ERR_STACK_OVERFLOW, + GETH_ERR_STACK_UNDERFLOW, + }, + state_db::Account, }; -use crate::operation::RWCounter; -use crate::state_db::Account; -use eth_types::evm_types::{stack::Stack, Gas, OpcodeId}; use eth_types::{ - address, bytecode, geth_types::GethData, word, Bytecode, Hash, ToAddress, ToWord, Word, + address, bytecode, + evm_types::{stack::Stack, Gas, OpcodeId}, + geth_types::GethData, + word, Bytecode, Hash, ToAddress, ToWord, Word, }; use lazy_static::lazy_static; -use mock::test_ctx::{helpers::*, LoggerConfig, TestContext}; -use mock::MOCK_COINBASE; +use mock::{ + test_ctx::{helpers::*, LoggerConfig, TestContext}, + MOCK_COINBASE, +}; use pretty_assertions::assert_eq; use std::collections::HashSet; @@ -25,7 +30,6 @@ struct CircuitInputBuilderTx { builder: CircuitInputBuilder, tx: Transaction, pub(crate) tx_ctx: TransactionContext, - step: ExecStep, } impl CircuitInputBuilderTx { @@ -47,19 +51,10 @@ impl CircuitInputBuilderTx { ) .unwrap(); - let prev_log_id = if tx.is_steps_empty() { - 0 - } else { - tx.last_step().log_id - }; - - let call_ctx = tx_ctx.call_ctx().unwrap(); - let exec_step = ExecStep::new(geth_step, call_ctx, RWCounter::new(), 0, prev_log_id); Self { builder, tx, tx_ctx, - step: exec_step, } } @@ -79,6 +74,7 @@ fn mock_internal_create() -> Call { Call { call_id: 0, caller_id: 0, + last_callee_id: 0, kind: CallKind::Create, is_static: false, is_root: false, @@ -95,10 +91,37 @@ fn mock_internal_create() -> Call { call_data_length: 0, return_data_offset: 0, return_data_length: 0, + last_callee_return_data_offset: 0, + last_callee_return_data_length: 0, + } +} + +fn mock_root_create() -> Call { + Call { + call_id: 0, + caller_id: 0, + last_callee_id: 0, + kind: CallKind::Create, + is_static: false, + is_root: true, + is_persistent: false, + is_success: false, + rw_counter_end_of_reversion: 0, + caller_address: *ADDR_A, + address: *ADDR_B, + code_source: CodeSource::Memory, + code_hash: Hash::zero(), + depth: 1, + value: Word::zero(), + call_data_offset: 0, + call_data_length: 0, + return_data_offset: 0, + return_data_length: 0, + last_callee_return_data_offset: 0, + last_callee_return_data_length: 0, } } -// // Geth Errors ignored // // These errors happen in a CALL, CALLCODE, DELEGATECALL or STATICCALL, and @@ -185,7 +208,7 @@ fn tracer_err_depth() { let mut builder = CircuitInputBuilderTx::new(&block, step); assert_eq!( builder.state_ref().get_step_err(step, next_step).unwrap(), - Some(ExecError::Depth) + Some(ExecError::Depth(DepthError::Call)) ); } @@ -227,10 +250,7 @@ fn tracer_err_insufficient_balance() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -254,7 +274,9 @@ fn tracer_err_insufficient_balance() { let mut builder = CircuitInputBuilderTx::new(&block, step); assert_eq!( builder.state_ref().get_step_err(step, next_step).unwrap(), - Some(ExecError::InsufficientBalance) + Some(ExecError::InsufficientBalance( + InsufficientBalanceError::Call + )) ); } @@ -323,12 +345,8 @@ fn tracer_err_address_collision() { // that outputs the same, which will lead to the same new // contract address. let code_creator = bytecode! { - PUSH1(0x00) // value - PUSH1(0x00) // offset - MSTORE - PUSH1(0x01) // length - PUSH1(0x00) // offset - RETURN + .op_mstore(0x00, 0x00) + .op_return(0x00, 0x01) }; // code_a calls code_b which executes code_creator in CREATE2 @@ -355,9 +373,7 @@ fn tracer_err_address_collision() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH3(0x123456) // salt @@ -389,10 +405,7 @@ fn tracer_err_address_collision() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -433,7 +446,127 @@ fn tracer_err_address_collision() { builder.builder.sdb.set_account( &ADDR_B, Account { - nonce: Word::zero(), + balance: Word::from(555u64), /* same value as in + * `mock::new_tracer_account` */ + ..Account::zero() + }, + ); + builder + .builder + .sdb + .set_account(&create2_address, Account::zero()); + assert_eq!( + builder.state_ref().get_step_err(step, next_step).unwrap(), + Some(ExecError::ContractAddressCollision) + ); +} + +#[test] +fn tracer_create_collision_free() { + // We do CREATE twice with the same parameters, with a code_creater + // that outputs not the same, which will lead to the different new + // contract address. + let code_creator = bytecode! { + .op_mstore(0x00, 0x00) + .op_return(0x00, 0x01) + }; + + // code_a calls code_b which executes code_creator in CREATE2 + let code_a = bytecode! { + PUSH1(0x0) // retLength + PUSH1(0x0) // retOffset + PUSH1(0x0) // argsLength + PUSH1(0x0) // argsOffset + PUSH1(0x0) // value + PUSH32(*WORD_ADDR_B) // addr + PUSH32(0x1_0000) // gas + CALL + + PUSH2(0xaa) + }; + + let mut code_b = Bytecode::default(); + // pad code_creator to multiple of 32 bytes + let len = code_creator.to_vec().len(); + let code_creator: Vec = code_creator + .to_vec() + .iter() + .cloned() + .chain(0u8..((32 - len % 32) as u8)) + .collect(); + for (index, word) in code_creator.chunks(32).enumerate() { + code_b.op_mstore(index * 32, Word::from_big_endian(word)); + } + let code_b_end = bytecode! { + PUSH1(len) // length + PUSH1(0x00) // offset + PUSH1(0x00) // value + CREATE + + PUSH1(len) // length + PUSH1(0x00) // offset + PUSH1(0x00) // value + CREATE + + PUSH3(0xbb) + }; + code_b.append(&code_b_end); + // Get the execution steps from the external tracer + let block: GethData = TestContext::<3, 2>::new_with_logger_config( + None, + |accs| { + accs[0] + .address(address!("0x0000000000000000000000000000000000000000")) + .code(code_a); + accs[1].address(*ADDR_B).code(code_b); + accs[2] + .address(address!("0x000000000000000000000000000000000cafe002")) + .balance(Word::from(1u64 << 30)); + }, + |mut txs, accs| { + txs[0].to(accs[0].address).from(accs[2].address); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); + }, + |block, _tx| block.number(0xcafeu64), + LoggerConfig::enable_memory(), + ) + .unwrap() + .into(); + + // get last CREATE + let (index, step) = block.geth_traces[0] + .struct_logs + .iter() + .enumerate() + .rev() + .find(|(_, s)| s.op == OpcodeId::CREATE) + .unwrap(); + let next_step = block.geth_traces[0].struct_logs.get(index + 1); + let memory = next_step.unwrap().memory.clone(); + + let create_address: Address = { + // get first RETURN + let (index, _) = block.geth_traces[0] + .struct_logs + .iter() + .enumerate() + .find(|(_, s)| s.op == OpcodeId::RETURN) + .unwrap(); + let next_step = block.geth_traces[0].struct_logs.get(index + 1); + let addr_word = next_step.unwrap().stack.last().unwrap(); + addr_word.to_address() + }; + + let mut builder = CircuitInputBuilderTx::new(&block, step); + // Set up call context at CREATE + builder.tx_ctx.call_is_success.push(false); + builder.state_ref().push_call(mock_internal_create()); + builder.state_ref().call_ctx_mut().unwrap().memory = memory; + // Set up account and contract that exist during the second CREATE2 + builder.builder.sdb.set_account( + &ADDR_B, + Account { + nonce: 0, balance: Word::from(555u64), /* same value as in * `mock::new_tracer_account` */ storage: HashMap::new(), @@ -441,18 +574,18 @@ fn tracer_err_address_collision() { }, ); builder.builder.sdb.set_account( - &create2_address, + &create_address, Account { - nonce: Word::zero(), + nonce: 0, balance: Word::zero(), storage: HashMap::new(), code_hash: Hash::zero(), }, ); - assert_eq!( - builder.state_ref().get_step_err(step, next_step).unwrap(), - Some(ExecError::ContractAddressCollision) - ); + + let error = builder.state_ref().get_step_err(step, next_step); + // expects no errors detected + assert_eq!(error.unwrap(), None); } fn check_err_code_store_out_of_gas(step: &GethExecStep, next_step: Option<&GethExecStep>) -> bool { @@ -469,12 +602,8 @@ fn tracer_err_code_store_out_of_gas() { // exhaust the gas to store the code. let code_len = 0x100; let code_creator = bytecode! { - PUSH1(Word::zero()) // value - PUSH32(code_len) // offset - MSTORE - PUSH32(code_len) // length - PUSH1(0x00) // offset - RETURN + .op_mstore(code_len, Word::zero()) + .op_return(0x00, code_len) }; // code_a calls code_b which executes code_creator in CREATE @@ -501,9 +630,7 @@ fn tracer_err_code_store_out_of_gas() { .chain(0..(32 - len % 32) as u8) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH32(len) // length @@ -528,10 +655,7 @@ fn tracer_err_code_store_out_of_gas() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -560,6 +684,57 @@ fn tracer_err_code_store_out_of_gas() { ); } +#[test] +fn tracer_err_code_store_out_of_gas_tx_deploy() { + // code_creator outputs an empty array of length 0x100, which will + // exhaust the gas to store the code. + let code_len = 0x100; + let code_creator = bytecode! { + .op_mstore(code_len, Word::zero()) + .op_return(0x00, code_len) + }; + + // Get the execution steps from the external tracer + let block: GethData = TestContext::<2, 1>::new_with_logger_config( + None, + |accs| { + accs[0].address(address!("0x0000000000000000000000000000000000000000")); + accs[1].address(*ADDR_B).balance(Word::from(1u64 << 30)); + }, + |mut txs, accs| { + txs[0] + .from(accs[1].address) + .gas(55000u64.into()) + .nonce(0) + .input(code_creator.into()); + }, + |block, _tx| block.number(0x0264), + LoggerConfig::enable_memory(), + ) + .unwrap() + .into(); + + // get last RETURN + let (index, step) = block.geth_traces[0] + .struct_logs + .iter() + .enumerate() + .rev() + .find(|(_, s)| s.op == OpcodeId::RETURN) + .unwrap(); + let next_step = block.geth_traces[0].struct_logs.get(index + 1); + assert!(check_err_code_store_out_of_gas(step, next_step)); + + let mut builder = CircuitInputBuilderTx::new(&block, step); + // Set up call context at CREATE + builder.tx_ctx.call_is_success.push(false); + builder.state_ref().push_call(mock_root_create()); + assert_eq!( + builder.state_ref().get_step_err(step, next_step).unwrap(), + Some(ExecError::CodeStoreOutOfGas) + ); +} + fn check_err_invalid_code(step: &GethExecStep, next_step: Option<&GethExecStep>) -> bool { let offset = step.stack.nth_last(0).unwrap(); let length = step.stack.nth_last(1).unwrap(); @@ -576,12 +751,8 @@ fn tracer_err_invalid_code() { // code_creator outputs byte array that starts with 0xef, which is // invalid code. let code_creator = bytecode! { - PUSH32(word!("0xef00000000000000000000000000000000000000000000000000000000000000")) // value - PUSH1(0x00) // offset - MSTORE - PUSH1(0x01) // length - PUSH1(0x00) // offset - RETURN + .op_mstore(0x00, word!("0xef00000000000000000000000000000000000000000000000000000000000000")) + .op_return(0x00, 0x01) }; // code_a calls code_b which executes code_creator in CREATE @@ -608,9 +779,7 @@ fn tracer_err_invalid_code() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH1(len) // length @@ -635,10 +804,7 @@ fn tracer_err_invalid_code() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -682,12 +848,8 @@ fn tracer_err_max_code_size_exceeded() { // trigger the max code size limit. let code_len = 0x6000 + 1; let code_creator = bytecode! { - PUSH1(Word::zero()) // value - PUSH32(code_len) // offset - MSTORE - PUSH32(code_len) // length - PUSH1(0x00) // offset - RETURN + .op_mstore(code_len, Word::zero()) + .op_return(0x00, code_len) }; // code_a calls code_b which executes code_creator in CREATE @@ -714,9 +876,7 @@ fn tracer_err_max_code_size_exceeded() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH32(len) // length @@ -741,10 +901,7 @@ fn tracer_err_max_code_size_exceeded() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -773,13 +930,62 @@ fn tracer_err_max_code_size_exceeded() { ); } +#[test] +fn tracer_err_max_code_size_exceeded_tx_deploy() { + // code_creator outputs an empty array of length 0x6000 + 1, which will + // trigger the max code size limit. + let code_len = 0x6000 + 1; + let code_creator = bytecode! { + .op_mstore(code_len, Word::zero()) + .op_return(0x00, code_len) + }; + + // Get the execution steps from the external tracer + let block: GethData = TestContext::<2, 1>::new_with_logger_config( + None, + |accs| { + accs[0].address(address!("0x0000000000000000000000000000000000000000")); + accs[1].address(*ADDR_B).balance(Word::from(1u64 << 30)); + }, + |mut txs, accs| { + txs[0] + .from(accs[1].address) + .gas(60000u64.into()) + .nonce(0) + .input(code_creator.into()); + }, + |block, _tx| block.number(0x0264), + LoggerConfig::enable_memory(), + ) + .unwrap() + .into(); + + // get last RETURN + let (index, step) = block.geth_traces[0] + .struct_logs + .iter() + .enumerate() + .rev() + .find(|(_, s)| s.op == OpcodeId::RETURN) + .unwrap(); + let next_step = block.geth_traces[0].struct_logs.get(index + 1); + assert!(check_err_max_code_size_exceeded(step, next_step)); + + let mut builder = CircuitInputBuilderTx::new(&block, step); + // Set up call context at RETURN + builder.tx_ctx.call_is_success.push(false); + builder.state_ref().push_call(mock_root_create()); + assert_eq!( + builder.state_ref().get_step_err(step, next_step).unwrap(), + Some(ExecError::MaxCodeSizeExceeded) + ); +} + #[test] fn tracer_create_stop() { // code_creator doesn't output anything because it stops. let code_creator = bytecode! { - PUSH32(word!("0xef00000000000000000000000000000000000000000000000000000000000000")) // value - PUSH1(0x00) // offset - MSTORE + .op_mstore(0x00, word!("0xef00000000000000000000000000000000000000000000000000000000000000")) PUSH1(0x01) // length PUSH1(0x00) // offset STOP @@ -809,9 +1015,7 @@ fn tracer_create_stop() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH1(len) // length @@ -838,10 +1042,7 @@ fn tracer_create_stop() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -868,7 +1069,6 @@ fn tracer_create_stop() { ); } -// // Geth Errors not reported // // These errors are specific to some opcodes and due to the way the tracing @@ -960,10 +1160,7 @@ fn tracer_err_invalid_jump() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1063,10 +1260,7 @@ fn tracer_err_execution_reverted() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1125,10 +1319,7 @@ fn tracer_stop() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1179,12 +1370,8 @@ fn tracer_err_return_data_out_of_bounds() { PUSH2(0xaa) }; let code_b = bytecode! { - PUSH2(0x42) // value - PUSH2(0x00) // offset - MSTORE - PUSH1(0x01) // length - PUSH1(0x00) // offset - RETURN + .op_mstore(0x00, 0x42) + .op_return(0x00, 0x01) }; // Get the execution steps from the external tracer let block: GethData = TestContext::<3, 2>::new_with_logger_config( @@ -1193,19 +1380,14 @@ fn tracer_err_return_data_out_of_bounds() { accs[0] .address(address!("0x0000000000000000000000000000000000000000")) .code(code_a); - accs[1] - .address(address!("0x000000000000000000000000000000000cafe001")) - .code(code_b); + accs[1].address(*ADDR_B).code(code_b); accs[2] .address(address!("0x000000000000000000000000000000000cafe002")) .balance(Word::from(1u64 << 30)); }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1231,7 +1413,6 @@ fn tracer_err_return_data_out_of_bounds() { ); } -// // Geth Errors Reported // // These errors can be found in the trace step error field. @@ -1241,9 +1422,7 @@ fn tracer_err_gas_uint_overflow() { // MSTORE a value at an offset so high that the gast cost is big enough // to overflow an uint64 let code = bytecode! { - PUSH32(0x42) // value - PUSH32(0x100_0000_0000_0000_0000_u128) // offset - MSTORE + .op_mstore(0x100_0000_0000_0000_0000_u128, 0x42) }; let block: GethData = TestContext::<2, 1>::new_with_logger_config( None, @@ -1282,7 +1461,7 @@ fn tracer_err_gas_uint_overflow() { fn tracer_err_invalid_opcode() { // The second opcode is invalid (0x0f) let mut code = bytecode::Bytecode::default(); - code.write_op(OpcodeId::PC); + code.op_pc(); code.write(0x0f, true); let block: GethData = TestContext::<2, 1>::new_with_logger_config( None, @@ -1317,7 +1496,16 @@ fn tracer_err_invalid_opcode() { } #[test] -fn tracer_err_write_protection() { +fn test_tracer_err_write_protection() { + // test write_protection error happens in sstore + tracer_err_write_protection(false); + // test write_protection error happens in call + tracer_err_write_protection(true); +} + +// this helper generates write_protection error for sstore by default, if +// is_call, for call opcode. +fn tracer_err_write_protection(is_call: bool) { // code_a calls code_b via static call, which tries to SSTORE and fails. let code_a = bytecode! { PUSH1(0x0) // retLength @@ -1330,13 +1518,14 @@ fn tracer_err_write_protection() { PUSH2(0xaa) }; - let code_b = bytecode! { - PUSH1(0x01) // value - PUSH1(0x02) // key - SSTORE + let mut code_b = Bytecode::default(); + if is_call { + code_b.op_call(0x1000, *WORD_ADDR_B, 0x10, 0x20, 0, 0x02, 0x01); + } else { + code_b.op_sstore(0x02, 0x01); + } + code_b.push(2, Word::from(0xbb)); - PUSH3(0xbb) - }; // Get the execution steps from the external tracer let block: GethData = TestContext::<3, 2>::new_with_logger_config( None, @@ -1351,10 +1540,7 @@ fn tracer_err_write_protection() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1362,16 +1548,22 @@ fn tracer_err_write_protection() { .unwrap() .into(); - let index = 9; // SSTORE + let index = if is_call { 14 } else { 9 }; let step = &block.geth_traces[0].struct_logs[index]; let next_step = block.geth_traces[0].struct_logs.get(index + 1); - assert_eq!(step.op, OpcodeId::SSTORE); + let opcode = if is_call { + OpcodeId::CALL + } else { + OpcodeId::SSTORE + }; + assert_eq!(step.op, opcode); let mut builder = CircuitInputBuilderTx::new(&block, step); builder.tx_ctx.call_is_success.push(false); builder.state_ref().push_call(Call { call_id: 0, caller_id: 0, + last_callee_id: 0, kind: CallKind::StaticCall, is_static: true, is_root: false, @@ -1388,6 +1580,8 @@ fn tracer_err_write_protection() { call_data_length: 0, return_data_offset: 0, return_data_length: 0, + last_callee_return_data_offset: 0, + last_callee_return_data_length: 0, }); assert_eq!( @@ -1487,7 +1681,6 @@ fn tracer_err_stack_underflow() { ); } -// // Circuit Input Builder tests // @@ -1495,12 +1688,8 @@ fn tracer_err_stack_underflow() { fn create2_address() { // code_creator outputs 0x6050. let code_creator = bytecode! { - PUSH32(word!("0x6050000000000000000000000000000000000000000000000000000000000000")) // value - PUSH1(0x00) // offset - MSTORE - PUSH1(0x02) // length - PUSH1(0x00) // offset - RETURN + .op_mstore(0x00, word!("0x6050000000000000000000000000000000000000000000000000000000000000")) + .op_return(0x00, 0x02) }; // code_a calls code_b which executes code_creator in CREATE @@ -1527,9 +1716,7 @@ fn create2_address() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH3(0x123456) // salt @@ -1555,10 +1742,7 @@ fn create2_address() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1597,12 +1781,8 @@ fn create2_address() { fn create_address() { // code_creator outputs 0x6050. let code_creator = bytecode! { - PUSH32(word!("0x6050000000000000000000000000000000000000000000000000000000000000")) // value - PUSH1(0x00) // offset - MSTORE - PUSH1(0x02) // length - PUSH1(0x00) // offset - RETURN + .op_mstore(0x00, word!("0x6050000000000000000000000000000000000000000000000000000000000000")) + .op_return(0x00, 0x02) }; // code_a calls code_b which executes code_creator in CREATE @@ -1629,9 +1809,7 @@ fn create_address() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } // We do CREATE 2 times to use a nonce != 0 in the second one. let code_b_end = bytecode! { @@ -1662,10 +1840,7 @@ fn create_address() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1698,10 +1873,8 @@ fn create_address() { builder.builder.sdb.set_account( &ADDR_B, Account { - nonce: Word::from(1), - balance: Word::zero(), - storage: HashMap::new(), - code_hash: Hash::zero(), + nonce: 1, + ..Account::zero() }, ); let addr = builder.state_ref().create_address().unwrap(); @@ -1729,9 +1902,7 @@ fn test_gen_access_trace() { PUSH2(0xaa) }; let code_b = bytecode! { - PUSH32(word!("0x1234567890000000000000000000abcdef000000000000000000112233445566")) // value - PUSH1(0x01) // offset - MSTORE + .op_mstore(0x01, word!("0x1234567890000000000000000000abcdef000000000000000000112233445566")) PUSH1(0x01) // value PUSH1(0x02) // key SSTORE @@ -1753,10 +1924,7 @@ fn test_gen_access_trace() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), @@ -1956,9 +2124,7 @@ fn test_gen_access_trace_create_push_call_stack() { .chain(0u8..((32 - len % 32) as u8)) .collect(); for (index, word) in code_creator.chunks(32).enumerate() { - code_b.push(32, Word::from_big_endian(word)); - code_b.push(32, Word::from(index * 32)); - code_b.write_op(OpcodeId::MSTORE); + code_b.op_mstore(index * 32, Word::from_big_endian(word)); } let code_b_end = bytecode! { PUSH1(len) // length @@ -1980,10 +2146,7 @@ fn test_gen_access_trace_create_push_call_stack() { }, |mut txs, accs| { txs[0].to(accs[0].address).from(accs[2].address); - txs[1] - .to(accs[1].address) - .from(accs[2].address) - .nonce(Word::one()); + txs[1].to(accs[1].address).from(accs[2].address).nonce(1); }, |block, _tx| block.number(0xcafeu64), LoggerConfig::enable_memory(), diff --git a/bus-mapping/src/circuit_input_builder/transaction.rs b/bus-mapping/src/circuit_input_builder/transaction.rs index 0c4d053c44..dae4f1db35 100644 --- a/bus-mapping/src/circuit_input_builder/transaction.rs +++ b/bus-mapping/src/circuit_input_builder/transaction.rs @@ -2,9 +2,7 @@ use std::collections::BTreeMap; -use eth_types::evm_types::Memory; -use eth_types::Signature; -use eth_types::{geth_types, Address, GethExecTrace, Word}; +use eth_types::{evm_types::Memory, geth_types, GethExecTrace}; use ethers_core::utils::get_contract_address; use crate::{ @@ -14,7 +12,7 @@ use crate::{ use super::{call::ReversionGroup, Call, CallContext, CallKind, CodeSource, ExecStep}; -#[derive(Debug)] +#[derive(Debug, Default)] /// Context of a [`Transaction`] which can mutate in an [`ExecStep`]. pub struct TransactionContext { /// Unique identifier of transaction of the block. The value is `index + 1`. @@ -178,49 +176,17 @@ impl TransactionContext { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] /// Result of the parsing of an Ethereum Transaction. pub struct Transaction { - /// Nonce - pub nonce: u64, - /// Gas - pub gas: u64, - /// Gas price - pub gas_price: Word, - /// From / Caller Address - pub from: Address, - /// To / Callee Address - pub to: Address, - /// Value - pub value: Word, - /// Input / Call Data - pub input: Vec, - /// Signature - pub signature: Signature, + /// The raw transaction fields + pub tx: geth_types::Transaction, /// Calls made in the transaction - calls: Vec, + pub(crate) calls: Vec, /// Execution steps steps: Vec, } -impl From<&Transaction> for geth_types::Transaction { - fn from(tx: &Transaction) -> geth_types::Transaction { - geth_types::Transaction { - from: tx.from, - to: Some(tx.to), - nonce: Word::from(tx.nonce), - gas_limit: Word::from(tx.gas), - value: tx.value, - gas_price: tx.gas_price, - call_data: tx.input.clone().into(), - v: tx.signature.v, - r: tx.signature.r, - s: tx.signature.s, - ..Default::default() - } - } -} - impl Transaction { /// Create a new Self. pub fn new( @@ -278,22 +244,9 @@ impl Transaction { }; Ok(Self { - nonce: eth_tx.nonce.as_u64(), - gas: eth_tx.gas.as_u64(), - gas_price: eth_tx.gas_price.unwrap_or_default(), - from: eth_tx.from, - to: eth_tx - .to - .unwrap_or_else(|| get_contract_address(eth_tx.from, eth_tx.nonce)), - value: eth_tx.value, - input: eth_tx.input.to_vec(), + tx: eth_tx.into(), calls: vec![call], steps: Vec::new(), - signature: Signature { - v: eth_tx.v.as_u64(), - r: eth_tx.r, - s: eth_tx.s, - }, }) } @@ -341,4 +294,9 @@ impl Transaction { pub fn is_steps_empty(&self) -> bool { self.steps.is_empty() } + + /// Convinient method for gas limit + pub fn gas(&self) -> u64 { + self.tx.gas_limit.as_u64() + } } diff --git a/bus-mapping/src/error.rs b/bus-mapping/src/error.rs index 0660993159..dca1721456 100644 --- a/bus-mapping/src/error.rs +++ b/bus-mapping/src/error.rs @@ -28,12 +28,12 @@ pub enum Error { /// Code not found in the CodeDB CodeNotFound(H256), /// Unable to figure out error at a [`GethExecStep`] - UnexpectedExecStepError(&'static str, GethExecStep), + UnexpectedExecStepError(&'static str, Box), /// Invalid [`eth_types::GethExecTrace`] due to an invalid/unexpected value /// in it. InvalidGethExecTrace(&'static str), /// Invalid [`GethExecStep`] due to an invalid/unexpected value in it. - InvalidGethExecStep(&'static str, GethExecStep), + InvalidGethExecStep(&'static str, Box), /// Eth type related error. EthTypeError(eth_types::Error), /// EVM Execution error @@ -73,8 +73,8 @@ pub enum OogError { /// Out of Gas for CREATE, RETURN, REVERT, which have dynamic memory /// expansion gas cost DynamicMemoryExpansion, - /// Out of Gas for CALLDATACOPY, CODECOPY, RETURNDATACOPY, which copy a - /// specified chunk of memory + /// Out of Gas for CALLDATACOPY, CODECOPY, EXTCODECOPY, RETURNDATACOPY, + /// which copy a specified chunk of memory MemoryCopy, /// Out of Gas for BALANCE, EXTCODESIZE, EXTCODEHASH, which possibly touch /// an extra account @@ -88,26 +88,47 @@ pub enum OogError { Exp, /// Out of Gas for SHA3 Sha3, - /// Out of Gas for EXTCODECOPY - ExtCodeCopy, - /// Out of Gas for SLOAD - Sload, - /// Out of Gas for SSTORE - Sstore, - /// Out of Gas for CALL + /// Out of Gas for SLOAD and SSTORE + SloadSstore, + /// Out of Gas for CALL, CALLCODE, DELEGATECALL and STATICCALL Call, - /// Out of Gas for CALLCODE - CallCode, - /// Out of Gas for DELEGATECALL - DelegateCall, /// Out of Gas for CREATE2 Create2, - /// Out of Gas for STATICCALL - StaticCall, /// Out of Gas for SELFDESTRUCT SelfDestruct, } +/// Insufficient balance errors by opcode/state. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum InsufficientBalanceError { + /// Insufficient balance during CALL/CALLCODE opcode. + Call, + /// Insufficient balance during CREATE opcode. + Create, + /// Insufficient balance during CREATE2 opcode. + Create2, +} + +/// Nonce uint overflow errors by opcode/state. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum NonceUintOverflowError { + /// Nonce uint overflow during CREATE opcode. + Create, + /// Nonce uint overflow during CREATE2 opcode. + Create2, +} + +/// Call depth errors by opcode/state. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum DepthError { + /// Call depth errors in CALL/CALLCODE opcode. + Call, + /// Call depth errors in CREATE opcode. + Create, + /// Call depth errors in CREATE2 opcode. + Create2, +} + /// EVM Execution Error #[derive(Clone, Debug, PartialEq, Eq)] pub enum ExecError { @@ -122,11 +143,11 @@ pub enum ExecError { /// For SSTORE, LOG0, LOG1, LOG2, LOG3, LOG4, CREATE, CALL, CREATE2, /// SELFDESTRUCT WriteProtection, - /// For CALL, CALLCODE, DELEGATECALL, STATICCALL - Depth, - /// For CALL, CALLCODE - InsufficientBalance, - /// For CREATE, CREATE2 + /// For CALL, CALLCODE, DELEGATECALL, STATICCALL, CREATE, CREATE2 + Depth(DepthError), + /// For CALL, CALLCODE, CREATE, CREATE2 + InsufficientBalance(InsufficientBalanceError), + /// For CREATE2 ContractAddressCollision, /// contract must not begin with 0xef due to EIP #3541 EVM Object Format /// (EOF) @@ -139,6 +160,8 @@ pub enum ExecError { CodeStoreOutOfGas, /// For RETURN in a CREATE, CREATE2 MaxCodeSizeExceeded, + /// For CREATE, CREATE2 + NonceUintOverflow(NonceUintOverflowError), } // TODO: Move to impl block. @@ -152,9 +175,10 @@ pub(crate) fn get_step_reported_error(op: &OpcodeId, error: &str) -> ExecError { OpcodeId::CREATE | OpcodeId::RETURN | OpcodeId::REVERT => { OogError::DynamicMemoryExpansion } - OpcodeId::CALLDATACOPY | OpcodeId::CODECOPY | OpcodeId::RETURNDATACOPY => { - OogError::MemoryCopy - } + OpcodeId::CALLDATACOPY + | OpcodeId::CODECOPY + | OpcodeId::EXTCODECOPY + | OpcodeId::RETURNDATACOPY => OogError::MemoryCopy, OpcodeId::BALANCE | OpcodeId::EXTCODESIZE | OpcodeId::EXTCODEHASH => { OogError::AccountAccess } @@ -163,14 +187,11 @@ pub(crate) fn get_step_reported_error(op: &OpcodeId, error: &str) -> ExecError { } OpcodeId::EXP => OogError::Exp, OpcodeId::SHA3 => OogError::Sha3, - OpcodeId::EXTCODECOPY => OogError::ExtCodeCopy, - OpcodeId::SLOAD => OogError::Sload, - OpcodeId::SSTORE => OogError::Sstore, - OpcodeId::CALL => OogError::Call, - OpcodeId::CALLCODE => OogError::CallCode, - OpcodeId::DELEGATECALL => OogError::DelegateCall, + OpcodeId::CALL | OpcodeId::CALLCODE | OpcodeId::DELEGATECALL | OpcodeId::STATICCALL => { + OogError::Call + } + OpcodeId::SLOAD | OpcodeId::SSTORE => OogError::SloadSstore, OpcodeId::CREATE2 => OogError::Create2, - OpcodeId::STATICCALL => OogError::StaticCall, OpcodeId::SELFDESTRUCT => OogError::SelfDestruct, _ => OogError::Constant, }; diff --git a/bus-mapping/src/evm.rs b/bus-mapping/src/evm.rs index 319040887a..39cd478c9f 100644 --- a/bus-mapping/src/evm.rs +++ b/bus-mapping/src/evm.rs @@ -5,5 +5,4 @@ pub(crate) mod opcodes; pub use eth_types::evm_types::opcode_ids::OpcodeId; pub use opcodes::Opcode; -#[cfg(any(feature = "test", test))] -pub use opcodes::{gen_sha3_code, MemoryKind}; +pub use opcodes::Sha3CodeGen; diff --git a/bus-mapping/src/evm/opcodes.rs b/bus-mapping/src/evm/opcodes.rs index 863f4894ee..cb4326ac66 100644 --- a/bus-mapping/src/evm/opcodes.rs +++ b/bus-mapping/src/evm/opcodes.rs @@ -1,25 +1,19 @@ //! Definition of each opcode of the EVM. use crate::{ - circuit_input_builder::{CircuitInputStateRef, ExecStep}, + circuit_input_builder::{CircuitInputStateRef, ExecState, ExecStep}, + error::{DepthError, ExecError, InsufficientBalanceError, NonceUintOverflowError, OogError}, evm::OpcodeId, - operation::{ - AccountField, CallContextField, TxAccessListAccountOp, TxReceiptField, TxRefundOp, RW, - }, + operation::TxAccessListAccountOp, Error, }; use core::fmt::Debug; -use eth_types::{ - evm_types::{GasCost, MAX_REFUND_QUOTIENT_OF_GAS_USED}, - GethExecStep, ToAddress, ToWord, Word, -}; -use keccak256::EMPTY_HASH; -use log::warn; +use eth_types::{evm_unimplemented, GethExecStep, ToAddress}; -#[cfg(any(feature = "test", test))] -pub use self::sha3::sha3_tests::{gen_sha3_code, MemoryKind}; +pub use self::sha3::Sha3CodeGen; mod address; mod balance; +mod begin_end_tx; mod calldatacopy; mod calldataload; mod calldatasize; @@ -31,6 +25,7 @@ mod codecopy; mod codesize; mod create; mod dup; +mod exp; mod extcodecopy; mod extcodehash; mod extcodesize; @@ -40,8 +35,9 @@ mod mload; mod mstore; mod number; mod origin; -mod r#return; +mod return_revert; mod returndatacopy; +mod returndatasize; mod selfbalance; mod sha3; mod sload; @@ -50,12 +46,23 @@ mod stackonlyop; mod stop; mod swap; +mod error_invalid_jump; +mod error_oog_call; +mod error_oog_exp; +mod error_oog_log; +mod error_oog_memory_copy; +mod error_oog_sload_sstore; +mod error_return_data_outofbound; +mod error_simple; +mod error_write_protection; + #[cfg(test)] mod memory_expansion_test; use self::sha3::Sha3; use address::Address; use balance::Balance; +use begin_end_tx::BeginEndTx; use calldatacopy::Calldatacopy; use calldataload::Calldataload; use calldatasize::Calldatasize; @@ -66,6 +73,16 @@ use codecopy::Codecopy; use codesize::Codesize; use create::DummyCreate; use dup::Dup; +use error_invalid_jump::InvalidJump; +use error_oog_call::OOGCall; +use error_oog_exp::OOGExp; +use error_oog_log::ErrorOOGLog; +use error_oog_memory_copy::OOGMemoryCopy; +use error_oog_sload_sstore::OOGSloadSstore; +use error_return_data_outofbound::ErrorReturnDataOutOfBound; +use error_simple::ErrorSimple; +use error_write_protection::ErrorWriteProtection; +use exp::Exponentiation; use extcodecopy::Extcodecopy; use extcodehash::Extcodehash; use extcodesize::Extcodesize; @@ -74,8 +91,9 @@ use logs::Log; use mload::Mload; use mstore::Mstore; use origin::Origin; -use r#return::Return; +use return_revert::ReturnRevert; use returndatacopy::Returndatacopy; +use returndatasize::Returndatasize; use selfbalance::Selfbalance; use sload::Sload; use sstore::Sstore; @@ -98,6 +116,15 @@ pub trait Opcode: Debug { ) -> Result, Error>; } +/// Generic trait for tx execution steps +/// which only supports ExecState::BeginTx and ExecState:EndTx +pub trait TxExecSteps: Debug { + fn gen_associated_steps( + state: &mut CircuitInputStateRef, + execution_step: ExecState, + ) -> Result; +} + #[derive(Debug, Copy, Clone)] struct Dummy; @@ -131,7 +158,6 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps { OpcodeId::SMOD => StackOnlyOpcode::<2, 1>::gen_associated_ops, OpcodeId::ADDMOD => StackOnlyOpcode::<3, 1>::gen_associated_ops, OpcodeId::MULMOD => StackOnlyOpcode::<3, 1>::gen_associated_ops, - OpcodeId::EXP => StackOnlyOpcode::<2, 1>::gen_associated_ops, OpcodeId::SIGNEXTEND => StackOnlyOpcode::<2, 1>::gen_associated_ops, OpcodeId::LT => StackOnlyOpcode::<2, 1>::gen_associated_ops, OpcodeId::GT => StackOnlyOpcode::<2, 1>::gen_associated_ops, @@ -159,9 +185,10 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps { OpcodeId::GASPRICE => GasPrice::gen_associated_ops, OpcodeId::CODECOPY => Codecopy::gen_associated_ops, OpcodeId::CODESIZE => Codesize::gen_associated_ops, + OpcodeId::EXP => Exponentiation::gen_associated_ops, OpcodeId::EXTCODESIZE => Extcodesize::gen_associated_ops, OpcodeId::EXTCODECOPY => Extcodecopy::gen_associated_ops, - OpcodeId::RETURNDATASIZE => StackOnlyOpcode::<0, 1>::gen_associated_ops, + OpcodeId::RETURNDATASIZE => Returndatasize::gen_associated_ops, OpcodeId::RETURNDATACOPY => Returndatacopy::gen_associated_ops, OpcodeId::EXTCODEHASH => Extcodehash::gen_associated_ops, OpcodeId::BLOCKHASH => StackOnlyOpcode::<1, 1>::gen_associated_ops, @@ -222,34 +249,73 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps { OpcodeId::LOG2 => Log::gen_associated_ops, OpcodeId::LOG3 => Log::gen_associated_ops, OpcodeId::LOG4 => Log::gen_associated_ops, - OpcodeId::CALL => CallOpcode::<7>::gen_associated_ops, - OpcodeId::STATICCALL => CallOpcode::<6>::gen_associated_ops, - OpcodeId::RETURN => Return::gen_associated_ops, - // REVERT is almost the same as RETURN - OpcodeId::REVERT => Return::gen_associated_ops, + OpcodeId::CALL | OpcodeId::CALLCODE => CallOpcode::<7>::gen_associated_ops, + OpcodeId::DELEGATECALL | OpcodeId::STATICCALL => CallOpcode::<6>::gen_associated_ops, + OpcodeId::RETURN | OpcodeId::REVERT => ReturnRevert::gen_associated_ops, OpcodeId::SELFDESTRUCT => { - warn!("Using dummy gen_selfdestruct_ops for opcode SELFDESTRUCT"); + evm_unimplemented!("Using dummy gen_selfdestruct_ops for opcode SELFDESTRUCT"); DummySelfDestruct::gen_associated_ops } - OpcodeId::CALLCODE | OpcodeId::DELEGATECALL => { - warn!("Using dummy gen_call_ops for opcode {:?}", opcode_id); - DummyCall::gen_associated_ops - } OpcodeId::CREATE => { - warn!("Using dummy gen_create_ops for opcode {:?}", opcode_id); + evm_unimplemented!("Using dummy gen_create_ops for opcode {:?}", opcode_id); DummyCreate::::gen_associated_ops } OpcodeId::CREATE2 => { - warn!("Using dummy gen_create_ops for opcode {:?}", opcode_id); + evm_unimplemented!("Using dummy gen_create_ops for opcode {:?}", opcode_id); DummyCreate::::gen_associated_ops } _ => { - warn!("Using dummy gen_associated_ops for opcode {:?}", opcode_id); + evm_unimplemented!("Using dummy gen_associated_ops for opcode {:?}", opcode_id); Dummy::gen_associated_ops } } } +fn fn_gen_error_state_associated_ops(error: &ExecError) -> Option { + match error { + ExecError::InvalidJump => Some(InvalidJump::gen_associated_ops), + ExecError::InvalidOpcode => Some(ErrorSimple::gen_associated_ops), + ExecError::OutOfGas(OogError::Call) => Some(OOGCall::gen_associated_ops), + ExecError::OutOfGas(OogError::Constant) => Some(ErrorSimple::gen_associated_ops), + ExecError::OutOfGas(OogError::Exp) => Some(OOGExp::gen_associated_ops), + ExecError::OutOfGas(OogError::Log) => Some(ErrorOOGLog::gen_associated_ops), + ExecError::OutOfGas(OogError::MemoryCopy) => Some(OOGMemoryCopy::gen_associated_ops), + ExecError::OutOfGas(OogError::SloadSstore) => Some(OOGSloadSstore::gen_associated_ops), + ExecError::StackOverflow => Some(ErrorSimple::gen_associated_ops), + ExecError::StackUnderflow => Some(ErrorSimple::gen_associated_ops), + // call & callcode can encounter InsufficientBalance error, Use pop-7 generic CallOpcode + ExecError::InsufficientBalance(InsufficientBalanceError::Call) => { + Some(CallOpcode::<7>::gen_associated_ops) + } + // create & create2 can encounter insufficient balance. + ExecError::InsufficientBalance(InsufficientBalanceError::Create) => { + Some(DummyCreate::::gen_associated_ops) + } + ExecError::InsufficientBalance(InsufficientBalanceError::Create2) => { + Some(DummyCreate::::gen_associated_ops) + } + // only create2 may cause ContractAddressCollision error, so use DummyCreate::. + ExecError::ContractAddressCollision => Some(DummyCreate::::gen_associated_ops), + // create & create2 can encounter nonce uint overflow. + ExecError::NonceUintOverflow(NonceUintOverflowError::Create) => { + Some(DummyCreate::::gen_associated_ops) + } + ExecError::NonceUintOverflow(NonceUintOverflowError::Create2) => { + Some(DummyCreate::::gen_associated_ops) + } + ExecError::WriteProtection => Some(ErrorWriteProtection::gen_associated_ops), + ExecError::ReturnDataOutOfBounds => Some(ErrorReturnDataOutOfBound::gen_associated_ops), + // call, callcode, create & create2 can encounter DepthError error, + ExecError::Depth(DepthError::Call) => Some(CallOpcode::<7>::gen_associated_ops), + ExecError::Depth(DepthError::Create) => Some(DummyCreate::::gen_associated_ops), + ExecError::Depth(DepthError::Create2) => Some(DummyCreate::::gen_associated_ops), + // more future errors place here + _ => { + evm_unimplemented!("TODO: error state {:?} not implemented", error); + None + } + } +} #[allow(clippy::collapsible_else_if)] /// Generate the associated operations according to the particular /// [`OpcodeId`]. @@ -258,8 +324,6 @@ pub fn gen_associated_ops( state: &mut CircuitInputStateRef, geth_steps: &[GethExecStep], ) -> Result, Error> { - let fn_gen_associated_ops = fn_gen_associated_ops(opcode_id); - let memory_enabled = !geth_steps.iter().all(|s| s.memory.is_empty()); if memory_enabled { assert_eq!( @@ -280,372 +344,52 @@ pub fn gen_associated_ops( }; if let Some(exec_error) = state.get_step_err(geth_step, next_step).unwrap() { log::warn!( - "geth error {:?} occurred in {:?}", + "geth error {:?} occurred in {:?} at pc {:?}", exec_error, - geth_step.op + geth_step.op, + geth_step.pc, ); - exec_step.error = Some(exec_error); - // for `oog_or_stack_error` error message will be returned by geth_step error - // field, when this kind of error happens, no more proceeding - if geth_step.op.is_call_or_create() && !exec_step.oog_or_stack_error() { - let call = state.parse_call(geth_step)?; - // Switch to callee's call context - state.push_call(call); - } - - state.handle_return(geth_step)?; - return Ok(vec![exec_step]); - } - // if no errors, continue as normal - fn_gen_associated_ops(state, geth_steps) -} - -pub fn gen_begin_tx_ops(state: &mut CircuitInputStateRef) -> Result { - let mut exec_step = state.new_begin_tx_step(); - let call = state.call()?.clone(); - - for (field, value) in [ - (CallContextField::TxId, state.tx_ctx.id().into()), - ( - CallContextField::RwCounterEndOfReversion, - call.rw_counter_end_of_reversion.into(), - ), - ( - CallContextField::IsPersistent, - (call.is_persistent as usize).into(), - ), - (CallContextField::IsSuccess, call.is_success.to_word()), - ] { - state.call_context_write(&mut exec_step, call.call_id, field, value); - } - - // Increase caller's nonce - let caller_address = call.caller_address; - let nonce_prev = state.sdb.increase_nonce(&caller_address); - state.account_write( - &mut exec_step, - caller_address, - AccountField::Nonce, - (nonce_prev + 1).into(), - nonce_prev.into(), - )?; - - // Add caller and callee into access list - for address in [call.caller_address, call.address] { - state.sdb.add_account_to_access_list(address); - state.tx_accesslist_account_write( - &mut exec_step, - state.tx_ctx.id(), - address, - true, - false, - )?; - } - - // Calculate intrinsic gas cost - let call_data_gas_cost = state - .tx - .input - .iter() - .fold(0, |acc, byte| acc + if *byte == 0 { 4 } else { 16 }); - let intrinsic_gas_cost = if state.tx.is_create() { - GasCost::CREATION_TX.as_u64() - } else { - GasCost::TX.as_u64() - } + call_data_gas_cost; - exec_step.gas_cost = GasCost(intrinsic_gas_cost); - - // Transfer with fee - state.transfer_with_fee( - &mut exec_step, - call.caller_address, - call.address, - call.value, - state.tx.gas_price * state.tx.gas, - )?; - - // Get code_hash of callee - let (_, callee_account) = state.sdb.get_account(&call.address); - let code_hash = callee_account.code_hash; - - // There are 4 branches from here. - match ( - call.is_create(), - state.is_precompiled(&call.address), - code_hash.to_fixed_bytes() == *EMPTY_HASH, - ) { - // 1. Creation transaction. - (true, _, _) => { - state.account_read( - &mut exec_step, - call.address, - AccountField::CodeHash, - call.code_hash.to_word(), - call.code_hash.to_word(), - )?; - for (field, value) in [ - (CallContextField::Depth, call.depth.into()), - ( - CallContextField::CallerAddress, - call.caller_address.to_word(), - ), - (CallContextField::CalleeAddress, call.address.to_word()), - ( - CallContextField::CallDataOffset, - call.call_data_offset.into(), - ), - ( - CallContextField::CallDataLength, - state.tx.input.len().into(), - ), - (CallContextField::Value, call.value), - (CallContextField::IsStatic, (call.is_static as usize).into()), - (CallContextField::LastCalleeId, 0.into()), - (CallContextField::LastCalleeReturnDataOffset, 0.into()), - (CallContextField::LastCalleeReturnDataLength, 0.into()), - (CallContextField::IsRoot, 1.into()), - (CallContextField::IsCreate, 1.into()), - (CallContextField::CodeHash, call.code_hash.to_word()), - ] { - state.call_context_write(&mut exec_step, call.call_id, field, value); - } - Ok(exec_step) - } - // 2. Call to precompiled. - (_, true, _) => { - warn!("Call to precompiled is left unimplemented"); - Ok(exec_step) - } - (_, _, is_empty_code_hash) => { - state.account_read( - &mut exec_step, - call.address, - AccountField::CodeHash, - code_hash.to_word(), - code_hash.to_word(), - )?; - - // 3. Call to account with empty code. - if is_empty_code_hash { - warn!("Call to account with empty code is left unimplemented"); - return Ok(exec_step); + exec_step.error = Some(exec_error.clone()); + // TODO: after more error state handled, refactor all error handling in + // fn_gen_error_state_associated_ops method + // For exceptions that have been implemented + if let Some(fn_gen_error_ops) = fn_gen_error_state_associated_ops(&exec_error) { + return fn_gen_error_ops(state, geth_steps); + } else { + // For exceptions that fail to enter next call context, we need + // to restore call context of current caller + let mut need_restore = true; + + // For exceptions that already enter next call context, but fail immediately + // (e.g. Depth, InsufficientBalance), we still need to parse the call. + if geth_step.op.is_call_or_create() { + let call = state.parse_call(geth_step)?; + state.push_call(call); + need_restore = false; } - // 4. Call to account with non-empty code. - for (field, value) in [ - (CallContextField::Depth, call.depth.into()), - ( - CallContextField::CallerAddress, - call.caller_address.to_word(), - ), - (CallContextField::CalleeAddress, call.address.to_word()), - ( - CallContextField::CallDataOffset, - call.call_data_offset.into(), - ), - ( - CallContextField::CallDataLength, - call.call_data_length.into(), - ), - (CallContextField::Value, call.value), - (CallContextField::IsStatic, (call.is_static as usize).into()), - (CallContextField::LastCalleeId, 0.into()), - (CallContextField::LastCalleeReturnDataOffset, 0.into()), - (CallContextField::LastCalleeReturnDataLength, 0.into()), - (CallContextField::IsRoot, 1.into()), - (CallContextField::IsCreate, 0.into()), - (CallContextField::CodeHash, code_hash.to_word()), - ] { - state.call_context_write(&mut exec_step, call.call_id, field, value); - } - - Ok(exec_step) + state.handle_return(&mut exec_step, geth_steps, need_restore)?; + return Ok(vec![exec_step]); } } + // if no errors, continue as normal + let fn_gen_associated_ops = fn_gen_associated_ops(opcode_id); + fn_gen_associated_ops(state, geth_steps) } -pub fn gen_end_tx_ops(state: &mut CircuitInputStateRef) -> Result { - let mut exec_step = state.new_end_tx_step(); - let call = state.tx.calls()[0].clone(); - - state.call_context_read( - &mut exec_step, - call.call_id, - CallContextField::TxId, - state.tx_ctx.id().into(), - ); - state.call_context_read( - &mut exec_step, - call.call_id, - CallContextField::IsPersistent, - Word::from(call.is_persistent as u8), - ); - - let refund = state.sdb.refund(); - state.push_op( - &mut exec_step, - RW::READ, - TxRefundOp { - tx_id: state.tx_ctx.id(), - value: refund, - value_prev: refund, - }, - ); - - let effective_refund = - refund.min((state.tx.gas - exec_step.gas_left.0) / MAX_REFUND_QUOTIENT_OF_GAS_USED as u64); - let (found, caller_account) = state.sdb.get_account_mut(&call.caller_address); - if !found { - return Err(Error::AccountNotFound(call.caller_address)); - } - let caller_balance_prev = caller_account.balance; - let caller_balance = - caller_balance_prev + state.tx.gas_price * (exec_step.gas_left.0 + effective_refund); - caller_account.balance = caller_balance; - - state.account_write( - &mut exec_step, - call.caller_address, - AccountField::Balance, - caller_balance, - caller_balance_prev, - )?; - - let effective_tip = state.tx.gas_price - state.block.base_fee; - let (found, coinbase_account) = state.sdb.get_account_mut(&state.block.coinbase); - if !found { - return Err(Error::AccountNotFound(state.block.coinbase)); - } - let coinbase_balance_prev = coinbase_account.balance; - let coinbase_balance = - coinbase_balance_prev + effective_tip * (state.tx.gas - exec_step.gas_left.0); - coinbase_account.balance = coinbase_balance; - state.account_write( - &mut exec_step, - state.block.coinbase, - AccountField::Balance, - coinbase_balance, - coinbase_balance_prev, - )?; - - // handle tx receipt tag - state.tx_receipt_write( - &mut exec_step, - state.tx_ctx.id(), - TxReceiptField::PostStateOrStatus, - call.is_persistent as u64, - )?; - - let log_id = exec_step.log_id; - state.tx_receipt_write( - &mut exec_step, - state.tx_ctx.id(), - TxReceiptField::LogLength, - log_id as u64, - )?; - - if state.tx_ctx.id() > 1 { - // query pre tx cumulative gas - state.tx_receipt_read( - &mut exec_step, - state.tx_ctx.id() - 1, - TxReceiptField::CumulativeGasUsed, - state.block_ctx.cumulative_gas_used, - )?; - } - - state.block_ctx.cumulative_gas_used += state.tx.gas - exec_step.gas_left.0; - state.tx_receipt_write( - &mut exec_step, - state.tx_ctx.id(), - TxReceiptField::CumulativeGasUsed, - state.block_ctx.cumulative_gas_used, - )?; - - if !state.tx_ctx.is_last_tx() { - state.call_context_read( - &mut exec_step, - state.block_ctx.rwc.0 + 1, - CallContextField::TxId, - (state.tx_ctx.id() + 1).into(), - ); - } - - Ok(exec_step) -} - -#[derive(Debug, Copy, Clone)] -struct DummyCall; - -impl Opcode for DummyCall { - fn gen_associated_ops( - state: &mut CircuitInputStateRef, - geth_steps: &[GethExecStep], - ) -> Result, Error> { - dummy_gen_call_ops(state, geth_steps) - } -} - -fn dummy_gen_call_ops( +pub fn gen_associated_steps( state: &mut CircuitInputStateRef, - geth_steps: &[GethExecStep], -) -> Result, Error> { - let geth_step = &geth_steps[0]; - let mut exec_step = state.new_step(geth_step)?; - - let (args_offset, args_length, ret_offset, ret_length) = { - // CALLCODE (gas, addr, value, argsOffset, argsLength, retOffset, retLength) - // DELEGATECALL(gas, addr, argsOffset, argsLength, retOffset, retLength) - // STATICCALL (gas, addr, argsOffset, argsLength, retOffset, retLength) - let pos = match geth_step.op { - OpcodeId::CALLCODE => (3, 4, 5, 6), - OpcodeId::DELEGATECALL | OpcodeId::STATICCALL => (2, 3, 4, 5), - _ => unreachable!("opcode is not of call type"), - }; - ( - geth_step.stack.nth_last(pos.0)?.as_usize(), - geth_step.stack.nth_last(pos.1)?.as_usize(), - geth_step.stack.nth_last(pos.2)?.as_usize(), - geth_step.stack.nth_last(pos.3)?.as_usize(), - ) + execution_step: ExecState, +) -> Result { + let fn_gen_associated_steps = match execution_step { + ExecState::BeginTx | ExecState::EndTx => BeginEndTx::gen_associated_steps, + _ => { + unreachable!() + } }; - state.call_expand_memory(args_offset, args_length, ret_offset, ret_length)?; - let tx_id = state.tx_ctx.id(); - let call = state.parse_call(geth_step)?; - - let (_, account) = state.sdb.get_account(&call.address); - let callee_code_hash = account.code_hash; - - let is_warm = state.sdb.check_account_in_access_list(&call.address); - state.push_op_reversible( - &mut exec_step, - RW::WRITE, - TxAccessListAccountOp { - tx_id, - address: call.address, - is_warm: true, - is_warm_prev: is_warm, - }, - )?; - - state.push_call(call.clone()); - - match ( - state.is_precompiled(&call.address), - callee_code_hash.to_fixed_bytes() == *EMPTY_HASH, - ) { - // 1. Call to precompiled. - (true, _) => Ok(vec![exec_step]), - // 2. Call to account with empty code. - (_, true) => { - state.handle_return(geth_step)?; - Ok(vec![exec_step]) - } - // 3. Call to account with non-empty code. - (_, false) => Ok(vec![exec_step]), - } + fn_gen_associated_steps(state, execution_step) } #[derive(Debug, Copy, Clone)] @@ -671,7 +415,6 @@ fn dummy_gen_selfdestruct_ops( let is_warm = state.sdb.check_account_in_access_list(&receiver); state.push_op_reversible( &mut exec_step, - RW::WRITE, TxAccessListAccountOp { tx_id: state.tx_ctx.id(), address: receiver, @@ -689,12 +432,14 @@ fn dummy_gen_selfdestruct_ops( return Err(Error::AccountNotFound(sender)); } let value = sender_account.balance; - state.transfer(&mut exec_step, sender, receiver, value)?; + // NOTE: In this dummy implementation we assume that the receiver already + // exists. + state.transfer(&mut exec_step, sender, receiver, true, false, value)?; if state.call()?.is_persistent { state.sdb.destruct_account(sender); } - state.handle_return(geth_step)?; + state.handle_return(&mut exec_step, geth_steps, false)?; Ok(vec![exec_step]) } diff --git a/bus-mapping/src/evm/opcodes/address.rs b/bus-mapping/src/evm/opcodes/address.rs index f196871755..208f97e59b 100644 --- a/bus-mapping/src/evm/opcodes/address.rs +++ b/bus-mapping/src/evm/opcodes/address.rs @@ -1,7 +1,9 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::operation::CallContextField; -use crate::Error; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + operation::CallContextField, + Error, +}; use eth_types::GethExecStep; #[derive(Clone, Copy, Debug)] @@ -41,8 +43,9 @@ impl Opcode for Address { mod address_tests { use super::*; use crate::{ - circuit_input_builder::ExecState, mock::BlockData, operation::CallContextOp, - operation::StackOp, operation::RW, + circuit_input_builder::ExecState, + mock::BlockData, + operation::{CallContextOp, StackOp, RW}, }; use eth_types::{ bytecode, diff --git a/bus-mapping/src/evm/opcodes/balance.rs b/bus-mapping/src/evm/opcodes/balance.rs index f578e8f454..1f58cf6712 100644 --- a/bus-mapping/src/evm/opcodes/balance.rs +++ b/bus-mapping/src/evm/opcodes/balance.rs @@ -1,8 +1,10 @@ -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::evm::Opcode; -use crate::operation::{TxAccessListAccountOp, RW}; -use crate::Error; -use eth_types::{GethExecStep, ToAddress, ToWord}; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + evm::Opcode, + operation::{AccountField, CallContextField, TxAccessListAccountOp}, + Error, +}; +use eth_types::{GethExecStep, ToAddress, ToWord, H256, U256}; #[derive(Debug, Copy, Clone)] pub(crate) struct Balance; @@ -12,20 +14,39 @@ impl Opcode for Balance { state: &mut CircuitInputStateRef, geth_steps: &[GethExecStep], ) -> Result, Error> { - // TODO: finish this, only access list part is done let geth_step = &geth_steps[0]; let mut exec_step = state.new_step(geth_step)?; - let address = geth_steps[0].stack.last()?.to_address(); - state.stack_read( + // Read account address from stack. + let address_word = geth_step.stack.last()?; + let address = address_word.to_address(); + state.stack_read(&mut exec_step, geth_step.stack.last_filled(), address_word)?; + + // Read transaction ID, rw_counter_end_of_reversion, and is_persistent + // from call context. + state.call_context_read( &mut exec_step, - geth_step.stack.last_filled(), - address.to_word(), - )?; + state.call()?.call_id, + CallContextField::TxId, + U256::from(state.tx_ctx.id()), + ); + state.call_context_read( + &mut exec_step, + state.call()?.call_id, + CallContextField::RwCounterEndOfReversion, + U256::from(state.call()?.rw_counter_end_of_reversion as u64), + ); + state.call_context_read( + &mut exec_step, + state.call()?.call_id, + CallContextField::IsPersistent, + U256::from(state.call()?.is_persistent as u64), + ); + + // Update transaction access list for account address. let is_warm = state.sdb.check_account_in_access_list(&address); state.push_op_reversible( &mut exec_step, - RW::WRITE, TxAccessListAccountOp { tx_id: state.tx_ctx.id(), address, @@ -34,6 +55,26 @@ impl Opcode for Balance { }, )?; + // Read account balance. + let account = state.sdb.get_account(&address).1; + let exists = !account.is_empty(); + let balance = account.balance; + let code_hash = if exists { + account.code_hash + } else { + H256::zero() + }; + state.account_read( + &mut exec_step, + address, + AccountField::CodeHash, + code_hash.to_word(), + ); + if exists { + state.account_read(&mut exec_step, address, AccountField::Balance, balance); + } + + // Write the BALANCE result to stack. state.stack_write( &mut exec_step, geth_steps[1].stack.nth_last_filled(0), @@ -43,3 +84,203 @@ impl Opcode for Balance { Ok(vec![exec_step]) } } + +#[cfg(test)] +mod balance_tests { + use super::*; + use crate::{ + circuit_input_builder::ExecState, + mock::BlockData, + operation::{AccountOp, CallContextOp, StackOp, RW}, + state_db::CodeDB, + }; + use eth_types::{ + address, bytecode, + evm_types::{OpcodeId, StackAddress}, + geth_types::GethData, + Bytecode, ToWord, Word, U256, + }; + use mock::TestContext; + use pretty_assertions::assert_eq; + + #[test] + fn test_balance_of_non_existing_address() { + test_ok(false, false); + } + + #[test] + fn test_balance_of_cold_address() { + test_ok(true, false); + } + + #[test] + fn test_balance_of_warm_address() { + test_ok(true, true); + } + + fn test_ok(exists: bool, is_warm: bool) { + let address = address!("0xaabbccddee000000000000000000000000000000"); + + // Pop balance first for warm account. + let mut code = Bytecode::default(); + if is_warm { + code.append(&bytecode! { + .op_balance(address) + POP + }); + } + code.append(&bytecode! { + .op_balance(address) + STOP + }); + + let balance = if exists { + Word::from(800u64) + } else { + Word::zero() + }; + + // Get the execution steps from the external tracer. + let block: GethData = TestContext::<3, 1>::new( + None, + |accs| { + accs[0] + .address(address!("0x0000000000000000000000000000000000000010")) + .balance(Word::from(1u64 << 20)) + .code(code.clone()); + if exists { + accs[1].address(address).balance(balance); + } else { + accs[1] + .address(address!("0x0000000000000000000000000000000000000020")) + .balance(Word::from(1u64 << 20)); + } + accs[2] + .address(address!("0x0000000000000000000000000000000000cafe01")) + .balance(Word::from(1u64 << 20)); + }, + |mut txs, accs| { + txs[0].to(accs[0].address).from(accs[2].address); + }, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap() + .into(); + + let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + + // Check if account address is in access list as a result of bus mapping. + assert!(builder.sdb.add_account_to_access_list(address)); + + let tx_id = 1; + let transaction = &builder.block.txs()[tx_id - 1]; + let call_id = transaction.calls()[0].call_id; + + let indices = transaction + .steps() + .iter() + .filter(|step| step.exec_state == ExecState::Op(OpcodeId::BALANCE)) + .last() + .unwrap() + .bus_mapping_instance + .clone(); + + let container = builder.block.container; + + let operation = &container.stack[indices[0].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + assert_eq!( + operation.op(), + &StackOp { + call_id, + address: StackAddress::from(1023u32), + value: address.to_word() + } + ); + + let operation = &container.call_context[indices[1].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + assert_eq!( + operation.op(), + &CallContextOp { + call_id, + field: CallContextField::TxId, + value: tx_id.into() + } + ); + + let operation = &container.call_context[indices[2].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + assert_eq!( + operation.op(), + &CallContextOp { + call_id, + field: CallContextField::RwCounterEndOfReversion, + value: U256::zero() + } + ); + + let operation = &container.call_context[indices[3].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + assert_eq!( + operation.op(), + &CallContextOp { + call_id, + field: CallContextField::IsPersistent, + value: U256::one() + } + ); + + let operation = &container.tx_access_list_account[indices[4].as_usize()]; + assert_eq!(operation.rw(), RW::WRITE); + assert_eq!( + operation.op(), + &TxAccessListAccountOp { + tx_id, + address, + is_warm: true, + is_warm_prev: is_warm + } + ); + + let code_hash = CodeDB::empty_code_hash().to_word(); + let operation = &container.account[indices[5].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + assert_eq!( + operation.op(), + &AccountOp { + address, + field: AccountField::CodeHash, + value: if exists { code_hash } else { U256::zero() }, + value_prev: if exists { code_hash } else { U256::zero() }, + } + ); + if exists { + let operation = &container.account[indices[6].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + assert_eq!( + operation.op(), + &AccountOp { + address, + field: AccountField::Balance, + value: balance, + value_prev: balance, + } + ); + } + + let operation = &container.stack[indices[6 + if exists { 1 } else { 0 }].as_usize()]; + assert_eq!(operation.rw(), RW::WRITE); + assert_eq!( + operation.op(), + &StackOp { + call_id, + address: 1023u32.into(), + value: balance, + } + ); + } +} diff --git a/bus-mapping/src/evm/opcodes/begin_end_tx.rs b/bus-mapping/src/evm/opcodes/begin_end_tx.rs new file mode 100644 index 0000000000..d7b6110aad --- /dev/null +++ b/bus-mapping/src/evm/opcodes/begin_end_tx.rs @@ -0,0 +1,327 @@ +use super::TxExecSteps; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecState, ExecStep}, + operation::{AccountField, AccountOp, CallContextField, TxReceiptField, TxRefundOp, RW}, + state_db::CodeDB, + Error, +}; +use eth_types::{ + evm_types::{GasCost, MAX_REFUND_QUOTIENT_OF_GAS_USED}, + evm_unimplemented, ToWord, Word, +}; +use ethers_core::utils::get_contract_address; + +#[derive(Clone, Copy, Debug)] +pub(crate) struct BeginEndTx; + +impl TxExecSteps for BeginEndTx { + fn gen_associated_steps( + state: &mut CircuitInputStateRef, + execution_step: ExecState, + ) -> Result { + match execution_step { + ExecState::BeginTx => gen_begin_tx_steps(state), + ExecState::EndTx => gen_end_tx_steps(state), + _ => { + unreachable!() + } + } + } +} + +fn gen_begin_tx_steps(state: &mut CircuitInputStateRef) -> Result { + let mut exec_step = state.new_begin_tx_step(); + let call = state.call()?.clone(); + + for (field, value) in [ + (CallContextField::TxId, state.tx_ctx.id().into()), + ( + CallContextField::RwCounterEndOfReversion, + call.rw_counter_end_of_reversion.into(), + ), + ( + CallContextField::IsPersistent, + (call.is_persistent as usize).into(), + ), + (CallContextField::IsSuccess, call.is_success.to_word()), + ] { + state.call_context_write(&mut exec_step, call.call_id, field, value); + } + + // Increase caller's nonce + let caller_address = call.caller_address; + let nonce_prev = state.sdb.get_account(&caller_address).1.nonce; + state.account_write( + &mut exec_step, + caller_address, + AccountField::Nonce, + (nonce_prev + 1).into(), + nonce_prev.into(), + )?; + + // Add caller and callee into access list + for address in [call.caller_address, call.address] { + let is_warm_prev = !state.sdb.add_account_to_access_list(address); + state.tx_accesslist_account_write( + &mut exec_step, + state.tx_ctx.id(), + address, + true, + is_warm_prev, + )?; + } + + let intrinsic_gas_cost = if state.tx.is_create() { + GasCost::CREATION_TX.as_u64() + } else { + GasCost::TX.as_u64() + } + state.tx.tx.call_data_gas_cost(); + exec_step.gas_cost = GasCost(intrinsic_gas_cost); + + // Get code_hash of callee + let (_, callee_account) = state.sdb.get_account(&call.address); + let callee_exists = !callee_account.is_empty(); + let (callee_code_hash, is_empty_code_hash) = if callee_exists { + ( + call.code_hash.to_word(), + call.code_hash == CodeDB::empty_code_hash(), + ) + } else { + (Word::zero(), true) + }; + if !state.is_precompiled(&call.address) && !call.is_create() { + state.account_read( + &mut exec_step, + call.address, + AccountField::CodeHash, + callee_code_hash, + ); + } + + // Transfer with fee + state.transfer_with_fee( + &mut exec_step, + call.caller_address, + call.address, + callee_exists, + call.is_create(), + call.value, + Some(state.tx.tx.gas_price * state.tx.gas()), + )?; + + // In case of contract creation we wish to verify the correctness of the + // contract's address (callee). This address is defined as: + // + // Keccak256(RLP([tx_caller, tx_nonce]))[12:] + // + // We feed the RLP-encoded bytes to the block's SHA3 inputs, which gets assigned + // to the Keccak circuit, so that the BeginTxGadget can do a lookup to the + // Keccak table and verify the contract address. + if state.tx.is_create() { + state.block.sha3_inputs.push({ + let mut stream = ethers_core::utils::rlp::RlpStream::new(); + stream.begin_list(2); + stream.append(&caller_address); + stream.append(&nonce_prev); + stream.out().to_vec() + }); + } + + // There are 4 branches from here. + match ( + call.is_create(), + state.is_precompiled(&call.address), + is_empty_code_hash, + ) { + // 1. Creation transaction. + (true, _, _) => { + state.push_op_reversible( + &mut exec_step, + AccountOp { + address: call.address, + field: AccountField::Nonce, + value: 1.into(), + value_prev: 0.into(), + }, + )?; + for (field, value) in [ + (CallContextField::Depth, call.depth.into()), + ( + CallContextField::CallerAddress, + call.caller_address.to_word(), + ), + ( + CallContextField::CalleeAddress, + get_contract_address(caller_address, nonce_prev).to_word(), + ), + ( + CallContextField::CallDataOffset, + call.call_data_offset.into(), + ), + ( + CallContextField::CallDataLength, + state.tx.tx.call_data.len().into(), + ), + (CallContextField::Value, call.value), + (CallContextField::IsStatic, (call.is_static as usize).into()), + (CallContextField::LastCalleeId, 0.into()), + (CallContextField::LastCalleeReturnDataOffset, 0.into()), + (CallContextField::LastCalleeReturnDataLength, 0.into()), + (CallContextField::IsRoot, 1.into()), + (CallContextField::IsCreate, 1.into()), + (CallContextField::CodeHash, call.code_hash.to_word()), + ] { + state.call_context_write(&mut exec_step, call.call_id, field, value); + } + Ok(exec_step) + } + // 2. Call to precompiled. + (_, true, _) => { + evm_unimplemented!("Call to precompiled is left unimplemented"); + Ok(exec_step) + } + (_, _, is_empty_code_hash) => { + // 3. Call to account with empty code. + if is_empty_code_hash { + return Ok(exec_step); + } + + // 4. Call to account with non-empty code. + for (field, value) in [ + (CallContextField::Depth, call.depth.into()), + ( + CallContextField::CallerAddress, + call.caller_address.to_word(), + ), + (CallContextField::CalleeAddress, call.address.to_word()), + ( + CallContextField::CallDataOffset, + call.call_data_offset.into(), + ), + ( + CallContextField::CallDataLength, + call.call_data_length.into(), + ), + (CallContextField::Value, call.value), + (CallContextField::IsStatic, (call.is_static as usize).into()), + (CallContextField::LastCalleeId, 0.into()), + (CallContextField::LastCalleeReturnDataOffset, 0.into()), + (CallContextField::LastCalleeReturnDataLength, 0.into()), + (CallContextField::IsRoot, 1.into()), + (CallContextField::IsCreate, 0.into()), + (CallContextField::CodeHash, callee_code_hash), + ] { + state.call_context_write(&mut exec_step, call.call_id, field, value); + } + + Ok(exec_step) + } + } +} + +fn gen_end_tx_steps(state: &mut CircuitInputStateRef) -> Result { + let mut exec_step = state.new_end_tx_step(); + let call = state.tx.calls()[0].clone(); + + state.call_context_read( + &mut exec_step, + call.call_id, + CallContextField::TxId, + state.tx_ctx.id().into(), + ); + state.call_context_read( + &mut exec_step, + call.call_id, + CallContextField::IsPersistent, + Word::from(call.is_persistent as u8), + ); + + let refund = state.sdb.refund(); + state.push_op( + &mut exec_step, + RW::READ, + TxRefundOp { + tx_id: state.tx_ctx.id(), + value: refund, + value_prev: refund, + }, + ); + + let effective_refund = refund + .min((state.tx.gas() - exec_step.gas_left.0) / MAX_REFUND_QUOTIENT_OF_GAS_USED as u64); + let (found, caller_account) = state.sdb.get_account(&call.caller_address); + if !found { + return Err(Error::AccountNotFound(call.caller_address)); + } + let caller_balance_prev = caller_account.balance; + let caller_balance = + caller_balance_prev + state.tx.tx.gas_price * (exec_step.gas_left.0 + effective_refund); + state.account_write( + &mut exec_step, + call.caller_address, + AccountField::Balance, + caller_balance, + caller_balance_prev, + )?; + + let effective_tip = state.tx.tx.gas_price - state.block.base_fee; + let (found, coinbase_account) = state.sdb.get_account(&state.block.coinbase); + if !found { + return Err(Error::AccountNotFound(state.block.coinbase)); + } + let coinbase_balance_prev = coinbase_account.balance; + let coinbase_balance = + coinbase_balance_prev + effective_tip * (state.tx.gas() - exec_step.gas_left.0); + state.account_write( + &mut exec_step, + state.block.coinbase, + AccountField::Balance, + coinbase_balance, + coinbase_balance_prev, + )?; + + // handle tx receipt tag + state.tx_receipt_write( + &mut exec_step, + state.tx_ctx.id(), + TxReceiptField::PostStateOrStatus, + call.is_persistent as u64, + )?; + + let log_id = exec_step.log_id; + state.tx_receipt_write( + &mut exec_step, + state.tx_ctx.id(), + TxReceiptField::LogLength, + log_id as u64, + )?; + + if state.tx_ctx.id() > 1 { + // query pre tx cumulative gas + state.tx_receipt_read( + &mut exec_step, + state.tx_ctx.id() - 1, + TxReceiptField::CumulativeGasUsed, + state.block_ctx.cumulative_gas_used, + )?; + } + + state.block_ctx.cumulative_gas_used += state.tx.gas() - exec_step.gas_left.0; + state.tx_receipt_write( + &mut exec_step, + state.tx_ctx.id(), + TxReceiptField::CumulativeGasUsed, + state.block_ctx.cumulative_gas_used, + )?; + + if !state.tx_ctx.is_last_tx() { + state.call_context_write( + &mut exec_step, + state.block_ctx.rwc.0 + 1, + CallContextField::TxId, + (state.tx_ctx.id() + 1).into(), + ); + } + + Ok(exec_step) +} diff --git a/bus-mapping/src/evm/opcodes/calldatacopy.rs b/bus-mapping/src/evm/opcodes/calldatacopy.rs index 0a2242a8bc..eb724c7e5e 100644 --- a/bus-mapping/src/evm/opcodes/calldatacopy.rs +++ b/bus-mapping/src/evm/opcodes/calldatacopy.rs @@ -1,8 +1,11 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::circuit_input_builder::{CopyDataType, CopyEvent, NumberOrHash}; -use crate::operation::{CallContextField, MemoryOp, RW}; -use crate::Error; +use crate::{ + circuit_input_builder::{ + CircuitInputStateRef, CopyDataType, CopyEvent, ExecStep, NumberOrHash, + }, + operation::CallContextField, + Error, +}; use eth_types::GethExecStep; #[derive(Clone, Copy, Debug)] @@ -14,35 +17,19 @@ impl Opcode for Calldatacopy { geth_steps: &[GethExecStep], ) -> Result, Error> { let geth_step = &geth_steps[0]; - let exec_steps = vec![gen_calldatacopy_step(state, geth_step)?]; + let mut exec_steps = vec![gen_calldatacopy_step(state, geth_step)?]; // reconstruction - let memory_offset = geth_step.stack.nth_last(0)?.as_u64(); - let data_offset = geth_step.stack.nth_last(1)?.as_u64(); - let length = geth_step.stack.nth_last(2)?.as_usize(); + let memory_offset = geth_step.stack.nth_last(0)?; + let data_offset = geth_step.stack.nth_last(1)?; + let length = geth_step.stack.nth_last(2)?; let call_ctx = state.call_ctx_mut()?; let memory = &mut call_ctx.memory; - if length != 0 { - let minimal_length = memory_offset as usize + length; - memory.extend_at_least(minimal_length); - - let mem_starts = memory_offset as usize; - let mem_ends = mem_starts + length as usize; - let data_starts = data_offset as usize; - let data_ends = data_starts + length as usize; - let call_data = &call_ctx.call_data; - if data_ends <= call_data.len() { - memory.0[mem_starts..mem_ends].copy_from_slice(&call_data[data_starts..data_ends]); - } else if let Some(actual_length) = call_data.len().checked_sub(data_starts) { - let mem_code_ends = mem_starts + actual_length; - memory.0[mem_starts..mem_code_ends].copy_from_slice(&call_data[data_starts..]); - // since we already resize the memory, no need to copy 0s for - // out of bound bytes - } - } + + memory.copy_from(memory_offset, data_offset, length, &call_ctx.call_data); let copy_event = gen_copy_event(state, geth_step)?; - state.push_copy(copy_event); + state.push_copy(&mut exec_steps[0], copy_event); Ok(exec_steps) } } @@ -105,64 +92,38 @@ fn gen_calldatacopy_step( Ok(exec_step) } -fn gen_copy_steps( - state: &mut CircuitInputStateRef, - exec_step: &mut ExecStep, - src_addr: u64, - dst_addr: u64, - src_addr_end: u64, - bytes_left: u64, - is_root: bool, -) -> Result, Error> { - let mut copy_steps = Vec::with_capacity(bytes_left as usize); - for idx in 0..bytes_left { - let addr = src_addr + idx; - let value = if addr < src_addr_end { - let byte = - state.call_ctx()?.call_data[(addr - state.call()?.call_data_offset) as usize]; - if !is_root { - state.push_op( - exec_step, - RW::READ, - MemoryOp::new(state.call()?.caller_id, addr.into(), byte), - ); - } - byte - } else { - 0 - }; - copy_steps.push((value, false)); - state.memory_write(exec_step, (dst_addr + idx).into(), value)?; - } - - Ok(copy_steps) -} - fn gen_copy_event( state: &mut CircuitInputStateRef, geth_step: &GethExecStep, ) -> Result { let rw_counter_start = state.block_ctx.rwc; - let memory_offset = geth_step.stack.nth_last(0)?.as_u64(); - let data_offset = geth_step.stack.nth_last(1)?.as_u64(); + + let memory_offset = geth_step.stack.nth_last(0)?; + let data_offset = geth_step.stack.nth_last(1)?; let length = geth_step.stack.nth_last(2)?.as_u64(); let call_data_offset = state.call()?.call_data_offset; let call_data_length = state.call()?.call_data_length; - let (src_addr, src_addr_end) = ( - call_data_offset + data_offset, - call_data_offset + call_data_length, - ); + + // Get low Uint64 of memory offset to generate copy steps. Since memory + // offset could be Uint64 overflow if memory length is zero. + let dst_addr = memory_offset.low_u64(); + let src_addr_end = call_data_offset.checked_add(call_data_length).unwrap(); + + // Reset start offset to end offset if overflow. + let src_addr = u64::try_from(data_offset) + .ok() + .and_then(|offset| offset.checked_add(call_data_offset)) + .unwrap_or(src_addr_end) + .min(src_addr_end); let mut exec_step = state.new_step(geth_step)?; - let copy_steps = gen_copy_steps( - state, + let copy_steps = state.gen_copy_steps_for_call_data( &mut exec_step, src_addr, - memory_offset, + dst_addr, src_addr_end, length, - state.call()?.is_root, )?; let (src_type, src_id) = if state.call()?.is_root { @@ -178,7 +139,7 @@ fn gen_copy_event( src_addr_end, dst_type: CopyDataType::Memory, dst_id: NumberOrHash::Number(state.call()?.call_id), - dst_addr: memory_offset, + dst_addr, log_id: None, rw_counter_start, bytes: copy_steps, @@ -196,10 +157,14 @@ mod calldatacopy_tests { bytecode, evm_types::{OpcodeId, StackAddress}, geth_types::GethData, - ToWord, Word, + Word, }; - use mock::test_ctx::{helpers::*, TestContext}; + use mock::{ + generate_mock_call_bytecode, + test_ctx::{helpers::*, TestContext}, + MockCallBytecodeParams, + }; use pretty_assertions::assert_eq; #[test] @@ -211,10 +176,7 @@ mod calldatacopy_tests { let offset = 0x00usize; let copy_size = 0x10usize; let code_b = bytecode! { - PUSH32(copy_size) // size - PUSH32(offset) // offset - PUSH32(dst_offset) // dst_offset - CALLDATACOPY + .op_calldatacopy(dst_offset, offset, copy_size) STOP }; @@ -224,24 +186,16 @@ mod calldatacopy_tests { .take(24) .chain(pushdata.clone()) .collect::>(); + let call_data_length = 0x20usize; let call_data_offset = 0x10usize; - let code_a = bytecode! { - // populate memory in A's context. - PUSH8(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call addr_b. - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH1(call_data_length) // argsLength - PUSH1(call_data_offset) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata, + call_data_length, + call_data_offset, + ..MockCallBytecodeParams::default() + }); // Get the execution steps from the external tracer let block: GethData = TestContext::<3, 1>::new( @@ -397,14 +351,8 @@ mod calldatacopy_tests { let (addr_a, addr_b) = (mock::MOCK_ACCOUNTS[0], mock::MOCK_ACCOUNTS[1]); // code B gets called by code A, so the call is an internal call. - let dst_offset = 0x00usize; - let offset = 0x00usize; - let copy_size = 0x50usize; let code_b = bytecode! { - PUSH32(copy_size) // size - PUSH32(offset) // offset - PUSH32(dst_offset) // dst_offset - CALLDATACOPY + .op_calldatacopy(0x00usize, 0x00usize, 0x50usize) STOP }; @@ -414,24 +362,13 @@ mod calldatacopy_tests { .take(24) .chain(pushdata.clone()) .collect::>(); - let call_data_length = 0x20usize; - let call_data_offset = 0x10usize; - let code_a = bytecode! { - // populate memory in A's context. - PUSH8(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call addr_b. - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH1(call_data_length) // argsLength - PUSH1(call_data_offset) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata, + call_data_length: 0x20usize, + call_data_offset: 0x10usize, + ..MockCallBytecodeParams::default() + }); // Get the execution steps from the external tracer let block: GethData = TestContext::<3, 1>::new( @@ -465,10 +402,7 @@ mod calldatacopy_tests { let calldata = vec![1, 3, 5, 7, 9, 2, 4, 6, 8]; let calldata_len = calldata.len(); let code = bytecode! { - PUSH32(size) - PUSH32(offset) - PUSH32(dst_offset) - CALLDATACOPY + .op_calldatacopy(dst_offset, offset, size) STOP }; @@ -580,7 +514,7 @@ mod calldatacopy_tests { assert_eq!(copy_events[0].bytes.len(), size); for (idx, (value, is_code)) in copy_events[0].bytes.iter().enumerate() { - assert_eq!(value, calldata.get(offset as usize + idx).unwrap_or(&0)); + assert_eq!(value, calldata.get(offset + idx).unwrap_or(&0)); assert!(!is_code); } } diff --git a/bus-mapping/src/evm/opcodes/calldataload.rs b/bus-mapping/src/evm/opcodes/calldataload.rs index dacee4e721..b28ae5d07c 100644 --- a/bus-mapping/src/evm/opcodes/calldataload.rs +++ b/bus-mapping/src/evm/opcodes/calldataload.rs @@ -23,73 +23,79 @@ impl Opcode for Calldataload { let offset = geth_step.stack.nth_last(0)?; state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(0), offset)?; - let is_root = state.call()?.is_root; - if is_root { - state.call_context_read( - &mut exec_step, - state.call()?.call_id, - CallContextField::TxId, - state.tx_ctx.id().into(), + // Check if offset is Uint64 overflow. + let calldata_word = if let Ok(offset) = u64::try_from(offset) { + let is_root = state.call()?.is_root; + let call_id = state.call()?.call_id; + if is_root { + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::TxId, + state.tx_ctx.id().into(), + ); + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::CallDataLength, + state.call()?.call_data_length.into(), + ); + } else { + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::CallerId, + state.call()?.caller_id.into(), + ); + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::CallDataLength, + state.call()?.call_data_length.into(), + ); + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::CallDataOffset, + state.call()?.call_data_offset.into(), + ); + } + + let call_data_offset = state.call()?.call_data_offset; + let call_data_length = state.call()?.call_data_length; + let (src_addr, src_addr_end, caller_id, call_data) = ( + call_data_offset + offset.min(call_data_length), + call_data_offset + call_data_length, + state.call()?.caller_id, + state.call_ctx()?.call_data.to_vec(), ); - state.call_context_read( - &mut exec_step, - state.call()?.call_id, - CallContextField::CallDataLength, - state.call()?.call_data_length.into(), - ); - } else { - state.call_context_read( - &mut exec_step, - state.call()?.call_id, - CallContextField::CallerId, - state.call()?.caller_id.into(), - ); - state.call_context_read( - &mut exec_step, - state.call()?.call_id, - CallContextField::CallDataLength, - state.call()?.call_data_length.into(), - ); - state.call_context_read( - &mut exec_step, - state.call()?.call_id, - CallContextField::CallDataOffset, - state.call()?.call_data_offset.into(), - ); - } - let call = state.call()?.clone(); - let (src_addr, src_addr_end, caller_id, call_data) = ( - call.call_data_offset as usize + offset.as_usize(), - call.call_data_offset as usize + call.call_data_length as usize, - call.caller_id, - state.call_ctx()?.call_data.to_vec(), - ); - let calldata_word = (0..32) - .map(|idx| { - let addr = src_addr + idx; - if addr < src_addr_end { - let byte = call_data[addr - call.call_data_offset as usize]; - if !is_root { - // caller id as call_id - state.push_op( - &mut exec_step, - RW::READ, - MemoryOp::new(caller_id, (src_addr + idx).into(), byte), - ); + let calldata: Vec<_> = (0..32) + .map(|idx| { + let addr = src_addr.checked_add(idx).unwrap_or(src_addr_end); + if addr < src_addr_end { + let byte = call_data[(addr - call_data_offset) as usize]; + if !is_root { + state.push_op( + &mut exec_step, + RW::READ, + MemoryOp::new(caller_id, (src_addr + idx).into(), byte), + ); + } + byte + } else { + 0 } - byte - } else { - 0 - } - }) - .collect::>(); + }) + .collect(); - state.stack_write( - &mut exec_step, - geth_step.stack.last_filled(), - U256::from_big_endian(&calldata_word), - )?; + U256::from_big_endian(&calldata) + } else { + // Stack push `0` as result if overflow. + U256::zero() + }; + + state.stack_write(&mut exec_step, geth_step.stack.last_filled(), calldata_word)?; Ok(vec![exec_step]) } @@ -102,9 +108,12 @@ mod calldataload_tests { bytecode, evm_types::{OpcodeId, StackAddress}, geth_types::GethData, - ToWord, Word, + Word, + }; + use mock::{ + generate_mock_call_bytecode, test_ctx::helpers::account_0_code_account_1_no_code, + MockCallBytecodeParams, TestContext, }; - use mock::{test_ctx::helpers::account_0_code_account_1_no_code, TestContext}; use rand::random; use crate::{circuit_input_builder::ExecState, mock::BlockData, operation::StackOp}; @@ -138,22 +147,13 @@ mod calldataload_tests { if memory_a.len() < call_data_length { memory_a.resize(call_data_length, 0); } - let code_a = bytecode! { - // populate memory in A's context. - PUSH32(Word::from_big_endian(&pushdata)) - PUSH1(0x00) // offset - MSTORE - // call addr_b - PUSH1(0x00) // retLength - PUSH1(0x00) // retOffset - PUSH1(call_data_length) // argsLength - PUSH1(call_data_offset) // argsOffset - PUSH1(0x00) // value - PUSH32(addr_b.to_word()) // addr - PUSH32(0x1_0000) // gas - CALL - STOP - }; + let code_a = generate_mock_call_bytecode(MockCallBytecodeParams { + address: addr_b, + pushdata, + call_data_length, + call_data_offset, + ..MockCallBytecodeParams::default() + }); // Get the execution steps from the external tracer let block: GethData = TestContext::<3, 1>::new( diff --git a/bus-mapping/src/evm/opcodes/caller.rs b/bus-mapping/src/evm/opcodes/caller.rs index 3e0956774c..1b7424a917 100644 --- a/bus-mapping/src/evm/opcodes/caller.rs +++ b/bus-mapping/src/evm/opcodes/caller.rs @@ -1,7 +1,9 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::operation::CallContextField; -use crate::Error; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + operation::CallContextField, + Error, +}; use eth_types::GethExecStep; /// Placeholder structure used to implement [`Opcode`] trait over it @@ -41,8 +43,9 @@ impl Opcode for Caller { mod caller_tests { use super::*; use crate::{ - circuit_input_builder::ExecState, mock::BlockData, operation::CallContextOp, - operation::StackOp, operation::RW, + circuit_input_builder::ExecState, + mock::BlockData, + operation::{CallContextOp, StackOp, RW}, }; use eth_types::{ bytecode, diff --git a/bus-mapping/src/evm/opcodes/callop.rs b/bus-mapping/src/evm/opcodes/callop.rs index 8cb4165916..b4fbdef3ec 100644 --- a/bus-mapping/src/evm/opcodes/callop.rs +++ b/bus-mapping/src/evm/opcodes/callop.rs @@ -1,19 +1,25 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::operation::{AccountField, CallContextField, TxAccessListAccountOp, RW}; -use crate::Error; -use eth_types::evm_types::gas_utils::{eip150_gas, memory_expansion_gas_cost}; -use eth_types::evm_types::GasCost; -use eth_types::{GethExecStep, ToWord}; -use keccak256::EMPTY_HASH; -use log::warn; +use crate::{ + circuit_input_builder::{CallKind, CircuitInputStateRef, CodeSource, ExecStep}, + operation::{AccountField, CallContextField, TxAccessListAccountOp}, + precompile::{execute_precompiled, is_precompiled}, + state_db::CodeDB, + Error, +}; +use eth_types::{ + evm_types::{ + gas_utils::{eip150_gas, memory_expansion_gas_cost}, + GasCost, + }, + GethExecStep, ToWord, Word, +}; +use std::cmp::min; /// Placeholder structure used to implement [`Opcode`] trait over it -/// corresponding to the `OpcodeId::CALL` and `OpcodeId::STATICCALL`. -/// - CALL: N_ARGS = 7 -/// - STATICCALL: N_ARGS = 6 -/// TODO: Suppose to add bus-mapping of `OpcodeId::CALLCODE` and -/// `OpcodeId::DELEGATECALL` here. +/// corresponding to the `OpcodeId::CALL`, `OpcodeId::CALLCODE`, +/// `OpcodeId::DELEGATECALL` and `OpcodeId::STATICCALL`. +/// - CALL and CALLCODE: N_ARGS = 7 +/// - DELEGATECALL and STATICCALL: N_ARGS = 6 #[derive(Debug, Copy, Clone)] pub(crate) struct CallOpcode; @@ -25,9 +31,11 @@ impl Opcode for CallOpcode { let geth_step = &geth_steps[0]; let mut exec_step = state.new_step(geth_step)?; - let args_offset = geth_step.stack.nth_last(N_ARGS - 4)?.as_usize(); + // In offset and length are truncated to Uint64 for call opcodes as: + // + let args_offset = geth_step.stack.nth_last(N_ARGS - 4)?.low_u64() as usize; let args_length = geth_step.stack.nth_last(N_ARGS - 3)?.as_usize(); - let ret_offset = geth_step.stack.nth_last(N_ARGS - 2)?.as_usize(); + let ret_offset = geth_step.stack.nth_last(N_ARGS - 2)?.low_u64() as usize; let ret_length = geth_step.stack.nth_last(N_ARGS - 1)?.as_usize(); // we need to keep the memory until parse_call complete @@ -37,26 +45,43 @@ impl Opcode for CallOpcode { let call = state.parse_call(geth_step)?; let current_call = state.call()?.clone(); - // NOTE: For `RwCounterEndOfReversion` we use the `0` value as a placeholder, - // and later set the proper value in - // `CircuitInputBuilder::set_value_ops_call_context_rwc_eor` - for (field, value) in [ + // For both CALLCODE and DELEGATECALL opcodes, `call.address` is caller + // address which is different from callee_address (code address). + let callee_address = match call.code_source { + CodeSource::Address(address) => address, + _ => call.address, + }; + + let mut field_values = vec![ (CallContextField::TxId, tx_id.into()), + // NOTE: For `RwCounterEndOfReversion` we use the `0` value as a + // placeholder, and later set the proper value in + // `CircuitInputBuilder::set_value_ops_call_context_rwc_eor` (CallContextField::RwCounterEndOfReversion, 0.into()), ( CallContextField::IsPersistent, (current_call.is_persistent as u64).into(), ), - ( - CallContextField::CalleeAddress, - current_call.address.to_word(), - ), ( CallContextField::IsStatic, (current_call.is_static as u64).into(), ), (CallContextField::Depth, current_call.depth.into()), - ] { + ( + CallContextField::CalleeAddress, + current_call.address.to_word(), + ), + ]; + if call.kind == CallKind::DelegateCall { + field_values.extend([ + ( + CallContextField::CallerAddress, + current_call.caller_address.to_word(), + ), + (CallContextField::Value, current_call.value), + ]); + } + for (field, value) in field_values { state.call_context_read(&mut exec_step, current_call.call_id, field, value); } @@ -74,13 +99,30 @@ impl Opcode for CallOpcode { (call.is_success as u64).into(), )?; - let is_warm = state.sdb.check_account_in_access_list(&call.address); + let callee_code_hash = call.code_hash; + let callee_exists = !state.sdb.get_account(&callee_address).1.is_empty(); + + let (callee_code_hash_word, is_empty_code_hash) = if callee_exists { + ( + callee_code_hash.to_word(), + callee_code_hash == CodeDB::empty_code_hash(), + ) + } else { + (Word::zero(), true) + }; + state.account_read( + &mut exec_step, + callee_address, + AccountField::CodeHash, + callee_code_hash_word, + ); + + let is_warm = state.sdb.check_account_in_access_list(&callee_address); state.push_op_reversible( &mut exec_step, - RW::WRITE, TxAccessListAccountOp { tx_id, - address: call.address, + address: callee_address, is_warm: true, is_warm_prev: is_warm, }, @@ -96,25 +138,52 @@ impl Opcode for CallOpcode { (call.is_persistent as u64).into(), ), ] { - state.call_context_write(&mut exec_step, call.call_id, field, value); + state.call_context_write(&mut exec_step, call.clone().call_id, field, value); } - state.transfer( + let (found, sender_account) = state.sdb.get_account(&call.caller_address); + debug_assert!(found); + + let caller_balance = sender_account.balance; + let is_call_or_callcode = call.kind == CallKind::Call || call.kind == CallKind::CallCode; + + // Precheck is OK when depth is in range and caller balance is sufficient + let is_precheck_ok = + geth_step.depth < 1025 && (!is_call_or_callcode || caller_balance >= call.value); + + log::debug!( + "is_precheck_ok: {}, call type: {:?}, sender_account: {:?} ", + is_precheck_ok, + call.kind, + call.caller_address + ); + + // read balance of caller to compare to value for insufficient_balance checking + // in circuit, also use for callcode successful case check balance is + // indeed larger than transfer value. for call opcode, it does in + // tranfer gadget implicitly. + state.account_read( &mut exec_step, call.caller_address, - call.address, - call.value, - )?; + AccountField::Balance, + caller_balance, + ); - let (_, callee_account) = state.sdb.get_account(&call.address); - let is_empty_account = callee_account.is_empty(); - let callee_nonce = callee_account.nonce; - let callee_code_hash = callee_account.code_hash; - for (field, value) in [ - (AccountField::Nonce, callee_nonce), - (AccountField::CodeHash, callee_code_hash.to_word()), - ] { - state.account_read(&mut exec_step, call.address, field, value, value)?; + let code_address = call.code_address(); + let is_precompile = code_address + .map(|ref addr| is_precompiled(addr)) + .unwrap_or(false); + // TODO: What about transfer for CALLCODE? + // Transfer value only for CALL opcode, is_precheck_ok = true. + if call.kind == CallKind::Call && is_precheck_ok { + state.transfer( + &mut exec_step, + call.caller_address, + call.address, + callee_exists || is_precompile, + false, + call.value, + )?; } // Calculate next_memory_word_size and callee_gas_left manually in case @@ -130,7 +199,7 @@ impl Opcode for CallOpcode { .max() .unwrap(); - let has_value = !call.value.is_zero(); + let has_value = !call.value.is_zero() && !call.is_delegatecall(); let memory_expansion_gas_cost = memory_expansion_gas_cost(curr_memory_word_size, next_memory_word_size); let gas_cost = if is_warm { @@ -139,7 +208,7 @@ impl Opcode for CallOpcode { GasCost::COLD_ACCOUNT_ACCESS.as_u64() } + if has_value { GasCost::CALL_WITH_VALUE.as_u64() - + if is_empty_account { + + if call.kind == CallKind::Call && !callee_exists { GasCost::NEW_ACCOUNT.as_u64() } else { 0 @@ -150,18 +219,63 @@ impl Opcode for CallOpcode { let gas_specified = geth_step.stack.last()?; let callee_gas_left = eip150_gas(geth_step.gas.0 - gas_cost, gas_specified); - // There are 3 branches from here. - match ( - state.is_precompiled(&call.address), - callee_code_hash.to_fixed_bytes() == *EMPTY_HASH, - ) { + // There are 4 branches from here. + // add failure case for insufficient balance or error depth in the future. + match (!is_precheck_ok, is_precompile, is_empty_code_hash) { // 1. Call to precompiled. - (true, _) => { - warn!("Call to precompiled is left unimplemented"); + (false, true, _) => { + assert!(call.is_success, "call to precompile should not fail"); + let caller_ctx = state.caller_ctx_mut()?; + let code_address = code_address.unwrap(); + let (result, contract_gas_cost) = execute_precompiled( + &code_address, + if args_length != 0 { + &caller_ctx.memory.0[args_offset..args_offset + args_length] + } else { + &[] + }, + callee_gas_left, + ); + log::trace!( + "precompile return data len {} gas {}", + result.len(), + contract_gas_cost + ); + caller_ctx.return_data = result.clone(); + let length = min(result.len(), ret_length); + if length != 0 { + caller_ctx.memory.extend_at_least(ret_offset + length); + } + caller_ctx.memory.0[ret_offset..ret_offset + length] + .copy_from_slice(&result[..length]); + for (field, value) in [ + (CallContextField::LastCalleeId, call.call_id.into()), + (CallContextField::LastCalleeReturnDataOffset, 0.into()), + ( + CallContextField::LastCalleeReturnDataLength, + result.len().into(), + ), + ] { + state.call_context_write(&mut exec_step, current_call.call_id, field, value); + } + + log::warn!("missing circuit part of precompile"); + state.handle_return(&mut exec_step, geth_steps, false)?; + + let real_cost = geth_steps[0].gas.0 - geth_steps[1].gas.0; + if real_cost != exec_step.gas_cost.0 { + log::warn!( + "precompile gas fixed from {} to {}, step {:?}", + exec_step.gas_cost.0, + real_cost, + geth_steps[0] + ); + } + exec_step.gas_cost = GasCost(real_cost); Ok(vec![exec_step]) } // 2. Call to account with empty code. - (_, true) => { + (false, _, true) => { for (field, value) in [ (CallContextField::LastCalleeId, 0.into()), (CallContextField::LastCalleeReturnDataOffset, 0.into()), @@ -169,11 +283,11 @@ impl Opcode for CallOpcode { ] { state.call_context_write(&mut exec_step, current_call.call_id, field, value); } - state.handle_return(geth_step)?; + state.handle_return(&mut exec_step, geth_steps, false)?; Ok(vec![exec_step]) } // 3. Call to account with non-empty code. - (_, false) => { + (false, _, false) => { for (field, value) in [ ( CallContextField::ProgramCounter, @@ -236,6 +350,404 @@ impl Opcode for CallOpcode { Ok(vec![exec_step]) } + + // 4. insufficient balance or error depth cases. + (true, _, _) => { + for (field, value) in [ + (CallContextField::LastCalleeId, 0.into()), + (CallContextField::LastCalleeReturnDataOffset, 0.into()), + (CallContextField::LastCalleeReturnDataLength, 0.into()), + ] { + state.call_context_write(&mut exec_step, current_call.call_id, field, value); + } + state.handle_return(&mut exec_step, geth_steps, false)?; + Ok(vec![exec_step]) + } // + } + } +} + +#[cfg(test)] +mod tests { + use crate::{circuit_input_builder::CircuitsParams, mock::BlockData}; + use eth_types::{bytecode, evm_types::OpcodeId, geth_types::GethData, word, Bytecode, Word}; + use mock::{ + test_ctx::{ + helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, + LoggerConfig, + }, + TestContext, + }; + + // move this to circuit after circuit part is complete + #[test] + fn test_precompiled_call() { + struct PrecompileCall { + name: &'static str, + setup_code: Bytecode, + ret_size: Word, + ret_offset: Word, + call_data_offset: Word, + call_data_length: Word, + address: Word, + value: Word, + gas: Word, + stack_value: Vec<(Word, Word)>, + max_rws: usize, + } + + impl Default for PrecompileCall { + fn default() -> Self { + PrecompileCall { + name: "precompiled call", + setup_code: Bytecode::default(), + ret_size: Word::from(0), + ret_offset: Word::from(0), + call_data_offset: Word::from(0), + call_data_length: Word::from(0), + address: Word::from(0), + value: Word::from(0), + gas: Word::from(0xFFFFFFF), + stack_value: vec![], + max_rws: 500, + } + } + } + + impl PrecompileCall { + fn with_call_op(&self, call_op: OpcodeId) -> Bytecode { + assert!( + call_op.is_call(), + "invalid setup, {:?} is not a call op", + call_op + ); + let mut code = self.setup_code.clone(); + code.push(32, self.ret_size) + .push(32, self.ret_offset) + .push(32, self.call_data_length) + .push(32, self.call_data_offset); + if call_op == OpcodeId::CALL || call_op == OpcodeId::CALLCODE { + code.push(32, self.value); + } + code.push(32, self.address) + .push(32, self.gas) + .write_op(call_op) + .write_op(OpcodeId::POP); + for (offset, _) in self.stack_value.iter().rev() { + code.push(32, *offset).write_op(OpcodeId::MLOAD); + } + + code + } + } + + let test_vector = [ + PrecompileCall { + name: "ecRecover", + setup_code: bytecode! { + PUSH32(word!("0x456e9aea5e197a1f1af7a3e85a3212fa4049a3ba34c2289b4c860fc0b0c64ef3")) // hash + PUSH1(0x0) + MSTORE + PUSH1(28) // v + PUSH1(0x20) + MSTORE + PUSH32(word!("0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608")) // r + PUSH1(0x40) + MSTORE + PUSH32(word!("0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada")) // s + PUSH1(0x60) + MSTORE + }, + ret_size: Word::from(0x20), + ret_offset: Word::from(0x80), + call_data_length: Word::from(0x80), + address: Word::from(0x1), + stack_value: vec![( + Word::from(0x80), + word!("7156526fbd7a3c72969b54f64e42c10fbb768c8a"), + )], + ..Default::default() + }, + PrecompileCall { + name: "SHA2-256", + setup_code: bytecode! { + PUSH1(0xFF) // data + PUSH1(0) + MSTORE + }, + ret_size: Word::from(0x20), + ret_offset: Word::from(0x20), + call_data_length: Word::from(0x1), + call_data_offset: Word::from(0x1F), + address: Word::from(0x2), + stack_value: vec![( + Word::from(0x20), + word!("a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89"), + )], + ..Default::default() + }, + PrecompileCall { + name: "RIPEMD-160", + setup_code: bytecode! { + PUSH1(0xFF) // data + PUSH1(0) + MSTORE + }, + ret_size: Word::from(0x20), + ret_offset: Word::from(0x20), + call_data_length: Word::from(0x1), + call_data_offset: Word::from(0x1F), + address: Word::from(0x3), + stack_value: vec![( + Word::from(0x20), + word!("2c0c45d3ecab80fe060e5f1d7057cd2f8de5e557"), + )], + ..Default::default() + }, + PrecompileCall { + name: "identity", + setup_code: bytecode! { + PUSH16(word!("0123456789ABCDEF0123456789ABCDEF")) + PUSH1(0x00) + MSTORE + }, + ret_size: Word::from(0x20), + ret_offset: Word::from(0x20), + call_data_length: Word::from(0x20), + address: Word::from(0x4), + stack_value: vec![(Word::from(0x20), word!("0123456789ABCDEF0123456789ABCDEF"))], + ..Default::default() + }, + PrecompileCall { + name: "modexp", + setup_code: bytecode! { + PUSH1(1) // Bsize + PUSH1(0) + MSTORE + PUSH1(1) // Esize + PUSH1(0x20) + MSTORE + PUSH1(1) // Msize + PUSH1(0x40) + MSTORE + PUSH32(word!("0x08090A0000000000000000000000000000000000000000000000000000000000")) // B, E and M + PUSH1(0x60) + MSTORE + }, + ret_size: Word::from(0x01), + ret_offset: Word::from(0x9F), + call_data_length: Word::from(0x63), + address: Word::from(0x5), + stack_value: vec![(Word::from(0x80), Word::from(8))], + ..Default::default() + }, + PrecompileCall { + name: "ecAdd", + setup_code: bytecode! { + PUSH1(1) // x1 + PUSH1(0) + MSTORE + PUSH1(2) // y1 + PUSH1(0x20) + MSTORE + PUSH1(1) // x2 + PUSH1(0x40) + MSTORE + PUSH1(2) // y2 + PUSH1(0x60) + MSTORE + }, + ret_size: Word::from(0x40), + ret_offset: Word::from(0x80), + call_data_length: Word::from(0x80), + address: Word::from(0x6), + stack_value: vec![ + ( + Word::from(0x80), + word!("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd3"), + ), + ( + Word::from(0xA0), + word!("15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4"), + ), + ], + ..Default::default() + }, + PrecompileCall { + name: "ecMul", + setup_code: bytecode! { + PUSH1(1) // x1 + PUSH1(0) + MSTORE + PUSH1(2) // y1 + PUSH1(0x20) + MSTORE + PUSH1(2) // s + PUSH1(0x40) + MSTORE + }, + ret_size: Word::from(0x40), + ret_offset: Word::from(0x60), + call_data_length: Word::from(0x60), + address: Word::from(0x7), + stack_value: vec![ + ( + Word::from(0x60), + word!("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd3"), + ), + ( + Word::from(0x80), + word!("15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4"), + ), + ], + ..Default::default() + }, + PrecompileCall { + name: "ecPairing", + setup_code: bytecode! { + PUSH32(word!("0x23a8eb0b0996252cb548a4487da97b02422ebc0e834613f954de6c7e0afdc1fc")) + PUSH32(word!("0x2a23af9a5ce2ba2796c1f4e453a370eb0af8c212d9dc9acd8fc02c2e907baea2")) + PUSH32(word!("0x091058a3141822985733cbdddfed0fd8d6c104e9e9eff40bf5abfef9ab163bc7")) + PUSH32(word!("0x1971ff0471b09fa93caaf13cbf443c1aede09cc4328f5a62aad45f40ec133eb4")) + PUSH32(word!("0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45")) + PUSH32(word!("0x0000000000000000000000000000000000000000000000000000000000000001")) + PUSH32(word!("0x2fe02e47887507adf0ff1743cbac6ba291e66f59be6bd763950bb16041a0a85e")) + PUSH32(word!("0x2bd368e28381e8eccb5fa81fc26cf3f048eea9abfdd85d7ed3ab3698d63e4f90")) + PUSH32(word!("0x22606845ff186793914e03e21df544c34ffe2f2f3504de8a79d9159eca2d98d9")) + PUSH32(word!("0x1fb19bb476f6b9e44e2a32234da8212f61cd63919354bc06aef31e3cfaff3ebc")) + PUSH32(word!("0x2c0f001f52110ccfe69108924926e45f0b0c868df0e7bde1fe16d3242dc715f6")) + PUSH32(word!("0x2cf44499d5d27bb186308b7af7af02ac5bc9eeb6a3d147c186b21fb1b76e18da")) + + PUSH1(12) + PUSH2(0x200) + MSTORE + + JUMPDEST + + PUSH2(0x200) + MLOAD + PUSH1(12) + SUB + PUSH1(0x20) + MUL + MSTORE + PUSH1(1) + PUSH2(0x200) + MLOAD + SUB + DUP1 + PUSH2(0x200) + MSTORE + PUSH2(0x192) + JUMPI + }, + ret_size: Word::from(0x20), + call_data_length: Word::from(0x180), + address: Word::from(0x8), + stack_value: vec![(Word::from(0x0), Word::from(1))], + max_rws: 3000, + ..Default::default() + }, + PrecompileCall { + name: "blake2f", + setup_code: bytecode! { + PUSH32(word!("0000000003000000000000000000000000000000010000000000000000000000")) + PUSH32(word!("0000000000000000000000000000000000000000000000000000000000000000")) + PUSH32(word!("0000000000000000000000000000000000000000000000000000000000000000")) + PUSH32(word!("0000000000000000000000000000000000000000000000000000000000000000")) + PUSH32(word!("19cde05b61626300000000000000000000000000000000000000000000000000")) + PUSH32(word!("3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e13")) + PUSH32(word!("0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f")) + + PUSH1(7) + PUSH2(0x160) + MSTORE + + JUMPDEST + + PUSH2(0x160) + MLOAD + PUSH1(7) + SUB + PUSH1(0x20) + MUL + MSTORE + PUSH1(1) + PUSH2(0x160) + MLOAD + SUB + DUP1 + PUSH2(0x160) + MSTORE + PUSH2(0xed) + JUMPI + }, + ret_size: Word::from(0x40), + ret_offset: Word::from(0x0), + call_data_length: Word::from(0xd5), + address: Word::from(0x9), + stack_value: vec![ + ( + Word::from(0x20), + word!("d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b"), + ), + ( + Word::from(0x0), + word!("8c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5"), + ), + ], + max_rws: 1500, + ..Default::default() + }, + ]; + + let call_ops = [ + OpcodeId::CALL, + OpcodeId::CALLCODE, + OpcodeId::DELEGATECALL, + OpcodeId::STATICCALL, + ]; + + for (test_call, call_op) in itertools::iproduct!(test_vector.iter(), call_ops.iter()) { + let code = test_call.with_call_op(*call_op); + let block: GethData = TestContext::<2, 1>::new_with_logger_config( + None, + account_0_code_account_1_no_code(code), + tx_from_1_to_0, + |block, _tx| block.number(0xcafeu64), + LoggerConfig { + enable_memory: true, + ..Default::default() + }, + ) + .unwrap() + .into(); + + let mut builder = BlockData::new_from_geth_data_with_params( + block.clone(), + CircuitsParams { + max_rws: test_call.max_rws, + ..Default::default() + }, + ) + .new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + + let step = block.geth_traces[0] + .struct_logs + .last() + .expect("at least one step"); + log::debug!("{:?}", step.stack); + for (offset, (_, stack_value)) in test_call.stack_value.iter().enumerate() { + assert_eq!( + *stack_value, + step.stack.nth_last(offset).expect("stack value not found"), + "stack output mismatch {}", + test_call.name + ); + } } } } diff --git a/bus-mapping/src/evm/opcodes/callvalue.rs b/bus-mapping/src/evm/opcodes/callvalue.rs index cd496b832e..7a8aaecffe 100644 --- a/bus-mapping/src/evm/opcodes/callvalue.rs +++ b/bus-mapping/src/evm/opcodes/callvalue.rs @@ -1,7 +1,9 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::operation::CallContextField; -use crate::Error; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + operation::CallContextField, + Error, +}; use eth_types::GethExecStep; /// Placeholder structure used to implement [`Opcode`] trait over it diff --git a/bus-mapping/src/evm/opcodes/chainid.rs b/bus-mapping/src/evm/opcodes/chainid.rs index 1dc7868ee1..b58a48e6c7 100644 --- a/bus-mapping/src/evm/opcodes/chainid.rs +++ b/bus-mapping/src/evm/opcodes/chainid.rs @@ -1,16 +1,21 @@ #[cfg(test)] mod chainid_tests { - use crate::operation::RW; - use crate::{circuit_input_builder::ExecState, mock::BlockData, operation::StackOp}; + use crate::{ + circuit_input_builder::ExecState, + mock::BlockData, + operation::{StackOp, RW}, + }; use eth_types::{ bytecode, evm_types::{OpcodeId, StackAddress}, geth_types::GethData, }; - use mock::test_ctx::{helpers::*, TestContext}; - use mock::MOCK_CHAIN_ID; + use mock::{ + test_ctx::{helpers::*, TestContext}, + MOCK_CHAIN_ID, + }; use pretty_assertions::assert_eq; #[test] diff --git a/bus-mapping/src/evm/opcodes/codecopy.rs b/bus-mapping/src/evm/opcodes/codecopy.rs index b6aa63436f..372c8d22af 100644 --- a/bus-mapping/src/evm/opcodes/codecopy.rs +++ b/bus-mapping/src/evm/opcodes/codecopy.rs @@ -17,39 +17,23 @@ impl Opcode for Codecopy { geth_steps: &[GethExecStep], ) -> Result, Error> { let geth_step = &geth_steps[0]; - let exec_steps = vec![gen_codecopy_step(state, geth_step)?]; + let mut exec_steps = vec![gen_codecopy_step(state, geth_step)?]; // reconstruction - - let dest_offset = geth_step.stack.nth_last(0)?.as_u64(); - let code_offset = geth_step.stack.nth_last(1)?.as_u64(); - let length = geth_step.stack.nth_last(2)?.as_u64(); + let dst_offset = geth_step.stack.nth_last(0)?; + let code_offset = geth_step.stack.nth_last(1)?; + let length = geth_step.stack.nth_last(2)?; let code_hash = state.call()?.code_hash; let code = state.code(code_hash)?; let call_ctx = state.call_ctx_mut()?; let memory = &mut call_ctx.memory; - if length != 0 { - let minimal_length = (dest_offset + length) as usize; - memory.extend_at_least(minimal_length); - let mem_starts = dest_offset as usize; - let mem_ends = mem_starts + length as usize; - let code_starts = code_offset as usize; - let code_ends = code_starts + length as usize; - if code_ends <= code.len() { - memory[mem_starts..mem_ends].copy_from_slice(&code[code_starts..code_ends]); - } else if let Some(actual_length) = code.len().checked_sub(code_starts) { - let mem_code_ends = mem_starts + actual_length; - memory[mem_starts..mem_code_ends].copy_from_slice(&code[code_starts..]); - // since we already resize the memory, no need to copy 0s for - // out of bound bytes - } - } + memory.copy_from(dst_offset, code_offset, length, &code); let copy_event = gen_copy_event(state, geth_step)?; - state.push_copy(copy_event); + state.push_copy(&mut exec_steps[0], copy_event); Ok(exec_steps) } } @@ -80,56 +64,48 @@ fn gen_codecopy_step( Ok(exec_step) } -fn gen_copy_steps( - state: &mut CircuitInputStateRef, - exec_step: &mut ExecStep, - src_addr: u64, - dst_addr: u64, - bytes_left: u64, - bytecode: &Bytecode, -) -> Result, Error> { - let mut steps = Vec::with_capacity(bytes_left as usize); - for idx in 0..bytes_left { - let addr = src_addr + idx; - let bytecode_element = bytecode.get(addr as usize).unwrap_or_default(); - steps.push((bytecode_element.value, bytecode_element.is_code)); - state.memory_write(exec_step, (dst_addr + idx).into(), bytecode_element.value)?; - } - Ok(steps) -} - fn gen_copy_event( state: &mut CircuitInputStateRef, geth_step: &GethExecStep, ) -> Result { let rw_counter_start = state.block_ctx.rwc; - let dst_offset = geth_step.stack.nth_last(0)?.as_u64(); - let code_offset = geth_step.stack.nth_last(1)?.as_u64(); + let dst_offset = geth_step.stack.nth_last(0)?; + let code_offset = geth_step.stack.nth_last(1)?; let length = geth_step.stack.nth_last(2)?.as_u64(); let code_hash = state.call()?.code_hash; let bytecode: Bytecode = state.code(code_hash)?.into(); - let src_addr_end = bytecode.to_vec().len() as u64; + let code_size = bytecode.code.len() as u64; + + // Get low Uint64 of offset to generate copy steps. Since offset could be + // Uint64 overflow if length is zero. + let dst_addr = dst_offset.low_u64(); + let src_addr_end = code_size; + + // Reset start offset to end offset if overflow. + let src_addr = u64::try_from(code_offset) + .unwrap_or(src_addr_end) + .min(src_addr_end); let mut exec_step = state.new_step(geth_step)?; - let copy_steps = gen_copy_steps( - state, + let copy_steps = state.gen_copy_steps_for_bytecode( &mut exec_step, - code_offset, - dst_offset, - length, &bytecode, + src_addr, + dst_addr, + src_addr_end, + length, )?; Ok(CopyEvent { src_type: CopyDataType::Bytecode, src_id: NumberOrHash::Hash(code_hash), - src_addr: code_offset, + src_addr, src_addr_end, dst_type: CopyDataType::Memory, dst_id: NumberOrHash::Number(state.call()?.call_id), - dst_addr: dst_offset, + dst_addr, log_id: None, rw_counter_start, bytes: copy_steps, @@ -142,9 +118,8 @@ mod codecopy_tests { bytecode, evm_types::{MemoryAddress, OpcodeId, StackAddress}, geth_types::GethData, - Word, H256, + Word, }; - use ethers_core::utils::keccak256; use mock::{ test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, TestContext, @@ -154,6 +129,7 @@ mod codecopy_tests { circuit_input_builder::{CopyDataType, ExecState, NumberOrHash}, mock::BlockData, operation::{MemoryOp, StackOp, RW}, + state_db::CodeDB, }; #[test] @@ -242,7 +218,7 @@ mod codecopy_tests { assert_eq!(copy_events[0].bytes.len(), size); assert_eq!( copy_events[0].src_id, - NumberOrHash::Hash(H256(keccak256(&code.to_vec()))) + NumberOrHash::Hash(CodeDB::hash(&code.to_vec())) ); assert_eq!(copy_events[0].src_addr as usize, code_offset); assert_eq!(copy_events[0].src_addr_end as usize, code.to_vec().len()); diff --git a/bus-mapping/src/evm/opcodes/create.rs b/bus-mapping/src/evm/opcodes/create.rs index 6c031d902b..2f6d40d409 100644 --- a/bus-mapping/src/evm/opcodes/create.rs +++ b/bus-mapping/src/evm/opcodes/create.rs @@ -1,9 +1,11 @@ -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::evm::Opcode; -use crate::operation::{AccountField, AccountOp, TxAccessListAccountOp, RW}; -use crate::Error; -use eth_types::{GethExecStep, ToWord}; -use keccak256::EMPTY_HASH; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + evm::Opcode, + operation::{AccountField, AccountOp, CallContextField, TxAccessListAccountOp}, + state_db::CodeDB, + Error, +}; +use eth_types::{evm_types::gas_utils::memory_expansion_gas_cost, GethExecStep, ToWord, Word}; #[derive(Debug, Copy, Clone)] pub struct DummyCreate; @@ -16,15 +18,19 @@ impl Opcode for DummyCreate { // TODO: replace dummy create here let geth_step = &geth_steps[0]; - let offset = geth_step.stack.nth_last(1)?.as_usize(); + // Get low Uint64 of offset to generate copy steps. Since offset could + // be Uint64 overflow if length is zero. + let offset = geth_step.stack.nth_last(1)?.low_u64() as usize; let length = geth_step.stack.nth_last(2)?.as_usize(); + let curr_memory_word_size = (state.call_ctx()?.memory.len() as u64) / 32; if length != 0 { state .call_ctx_mut()? .memory .extend_at_least(offset + length); } + let next_memory_word_size = (state.call_ctx()?.memory.len() as u64) / 32; let mut exec_step = state.new_step(geth_step)?; @@ -43,14 +49,20 @@ impl Opcode for DummyCreate { state.create_address()? }; + // TODO: rename this to initialization call? + let call = state.parse_call(geth_step)?; state.stack_write( &mut exec_step, geth_step.stack.nth_last_filled(n_pop - 1), - address.to_word(), + if call.is_success { + address.to_word() + } else { + Word::zero() + }, )?; let tx_id = state.tx_ctx.id(); - let call = state.parse_call(geth_step)?; + let current_call = state.call()?.clone(); // Quote from [EIP-2929](https://eips.ethereum.org/EIPS/eip-2929) // > When a CREATE or CREATE2 opcode is called, @@ -61,7 +73,6 @@ impl Opcode for DummyCreate { let is_warm = state.sdb.check_account_in_access_list(&address); state.push_op_reversible( &mut exec_step, - RW::WRITE, TxAccessListAccountOp { tx_id: state.tx_ctx.id(), address, @@ -74,7 +85,6 @@ impl Opcode for DummyCreate { let nonce_prev = state.sdb.get_nonce(&call.caller_address); state.push_op_reversible( &mut exec_step, - RW::WRITE, AccountOp { address: call.caller_address, field: AccountField::Nonce, @@ -87,7 +97,6 @@ impl Opcode for DummyCreate { let is_warm = state.sdb.check_account_in_access_list(&call.address); state.push_op_reversible( &mut exec_step, - RW::WRITE, TxAccessListAccountOp { tx_id, address: call.address, @@ -98,12 +107,20 @@ impl Opcode for DummyCreate { state.push_call(call.clone()); + state.transfer( + &mut exec_step, + call.caller_address, + call.address, + true, + true, + call.value, + )?; + // Increase callee's nonce let nonce_prev = state.sdb.get_nonce(&call.address); debug_assert!(nonce_prev == 0); state.push_op_reversible( &mut exec_step, - RW::WRITE, AccountOp { address: call.address, field: AccountField::Nonce, @@ -112,16 +129,56 @@ impl Opcode for DummyCreate { }, )?; - state.transfer( - &mut exec_step, - call.caller_address, - call.address, - call.value, - )?; + let memory_expansion_gas_cost = + memory_expansion_gas_cost(curr_memory_word_size, next_memory_word_size); + + // EIP-150: all but one 64th of the caller's gas is sent to the callee. + let caller_gas_left = + (geth_step.gas.0 - geth_step.gas_cost.0 - memory_expansion_gas_cost) / 64; + + for (field, value) in [ + ( + CallContextField::ProgramCounter, + (geth_step.pc.0 + 1).into(), + ), + ( + CallContextField::StackPointer, + geth_step.stack.nth_last_filled(n_pop - 1).0.into(), + ), + (CallContextField::GasLeft, caller_gas_left.into()), + (CallContextField::MemorySize, next_memory_word_size.into()), + ( + CallContextField::ReversibleWriteCounter, + // +3 is because we do some transfers after pushing the call. can be just push the + // call later? + (exec_step.reversible_write_counter + 3).into(), + ), + ] { + state.call_context_write(&mut exec_step, current_call.call_id, field, value); + } + + for (field, value) in [ + (CallContextField::CallerId, current_call.call_id.into()), + (CallContextField::IsSuccess, call.is_success.to_word()), + (CallContextField::IsPersistent, call.is_persistent.to_word()), + (CallContextField::TxId, state.tx_ctx.id().into()), + ( + CallContextField::CallerAddress, + current_call.address.to_word(), + ), + (CallContextField::CalleeAddress, call.address.to_word()), + ( + CallContextField::RwCounterEndOfReversion, + call.rw_counter_end_of_reversion.to_word(), + ), + (CallContextField::IsPersistent, call.is_persistent.to_word()), + ] { + state.call_context_write(&mut exec_step, call.call_id, field, value); + } - if call.code_hash.to_fixed_bytes() == *EMPTY_HASH { + if call.code_hash == CodeDB::empty_code_hash() { // 1. Create with empty initcode. - state.handle_return(geth_step)?; + state.handle_return(&mut exec_step, geth_steps, false)?; Ok(vec![exec_step]) } else { // 2. Create with non-empty initcode. diff --git a/bus-mapping/src/evm/opcodes/dup.rs b/bus-mapping/src/evm/opcodes/dup.rs index 27d0ec95e1..87f4f84d58 100644 --- a/bus-mapping/src/evm/opcodes/dup.rs +++ b/bus-mapping/src/evm/opcodes/dup.rs @@ -1,6 +1,8 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::Error; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + Error, +}; use eth_types::GethExecStep; /// Placeholder structure used to implement [`Opcode`] trait over it @@ -31,7 +33,10 @@ impl Opcode for Dup { #[cfg(test)] mod dup_tests { - use crate::{mock::BlockData, operation::StackOp, operation::RW}; + use crate::{ + mock::BlockData, + operation::{StackOp, RW}, + }; use eth_types::{bytecode, evm_types::StackAddress, geth_types::GethData, word}; use itertools::Itertools; use mock::test_ctx::{helpers::*, TestContext}; diff --git a/bus-mapping/src/evm/opcodes/error_invalid_jump.rs b/bus-mapping/src/evm/opcodes/error_invalid_jump.rs new file mode 100644 index 0000000000..0e72a9b949 --- /dev/null +++ b/bus-mapping/src/evm/opcodes/error_invalid_jump.rs @@ -0,0 +1,48 @@ +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + evm::{Opcode, OpcodeId}, + Error, +}; +use eth_types::{GethExecStep, Word}; + +#[derive(Debug, Copy, Clone)] +pub(crate) struct InvalidJump; + +impl Opcode for InvalidJump { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + let mut exec_step = state.new_step(geth_step)?; + let next_step = if geth_steps.len() > 1 { + Some(&geth_steps[1]) + } else { + None + }; + exec_step.error = state.get_step_err(geth_step, next_step).unwrap(); + // assert op code can only be JUMP or JUMPI + assert!(geth_step.op == OpcodeId::JUMP || geth_step.op == OpcodeId::JUMPI); + let is_jumpi = geth_step.op == OpcodeId::JUMPI; + let mut condition: Word = Word::zero(); + if is_jumpi { + condition = geth_step.stack.nth_last(1)?; + } + state.stack_read( + &mut exec_step, + geth_step.stack.last_filled(), + geth_step.stack.last()?, + )?; + if is_jumpi { + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(1), + condition, + )?; + } + + // `IsSuccess` call context operation is added in handle_return + state.handle_return(&mut exec_step, geth_steps, true)?; + Ok(vec![exec_step]) + } +} diff --git a/bus-mapping/src/evm/opcodes/error_oog_call.rs b/bus-mapping/src/evm/opcodes/error_oog_call.rs new file mode 100644 index 0000000000..a46423f097 --- /dev/null +++ b/bus-mapping/src/evm/opcodes/error_oog_call.rs @@ -0,0 +1,96 @@ +use super::Opcode; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + operation::{AccountField, CallContextField, TxAccessListAccountOp, RW}, + Error, +}; +use eth_types::{evm_types::OpcodeId, GethExecStep, ToAddress, ToWord, Word}; + +/// Placeholder structure used to implement [`Opcode`] trait over it +/// corresponding to the out of gas errors for [`OpcodeId::CALL`], +/// [`OpcodeId::CALLCODE`], [`OpcodeId::DELEGATECALL`] and +/// [`OpcodeId::STATICCALL`]. +#[derive(Debug, Copy, Clone)] +pub(crate) struct OOGCall; + +impl Opcode for OOGCall { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + let stack_input_num = match geth_step.op { + OpcodeId::CALL | OpcodeId::CALLCODE => 7, + OpcodeId::DELEGATECALL | OpcodeId::STATICCALL => 6, + op => unreachable!("{op} should not happen in OOGCall"), + }; + + let mut exec_step = state.new_step(geth_step)?; + let next_step = if geth_steps.len() > 1 { + Some(&geth_steps[1]) + } else { + None + }; + exec_step.error = state.get_step_err(geth_step, next_step).unwrap(); + + let tx_id = state.tx_ctx.id(); + let call_address = geth_step.stack.nth_last(1)?.to_address(); + + let current_call = state.call()?.clone(); + for (field, value) in [ + (CallContextField::TxId, tx_id.into()), + ( + CallContextField::IsStatic, + (current_call.is_static as u64).into(), + ), + ] { + state.call_context_read(&mut exec_step, current_call.call_id, field, value); + } + + for i in 0..stack_input_num { + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(i), + geth_step.stack.nth_last(i)?, + )?; + } + + state.stack_write( + &mut exec_step, + geth_step.stack.nth_last_filled(stack_input_num - 1), + // Must fail. + (0_u64).into(), + )?; + + let (_, callee_account) = state.sdb.get_account(&call_address); + let callee_exists = !callee_account.is_empty(); + let callee_code_hash = callee_account.code_hash; + let callee_code_hash_word = if callee_exists { + callee_code_hash.to_word() + } else { + Word::zero() + }; + + state.account_read( + &mut exec_step, + call_address, + AccountField::CodeHash, + callee_code_hash_word, + ); + + let is_warm = state.sdb.check_account_in_access_list(&call_address); + state.push_op( + &mut exec_step, + RW::READ, + TxAccessListAccountOp { + tx_id, + address: call_address, + is_warm, + is_warm_prev: is_warm, + }, + ); + + state.handle_return(&mut exec_step, geth_steps, true)?; + Ok(vec![exec_step]) + } +} diff --git a/bus-mapping/src/evm/opcodes/error_oog_exp.rs b/bus-mapping/src/evm/opcodes/error_oog_exp.rs new file mode 100644 index 0000000000..a0d7f5bdc2 --- /dev/null +++ b/bus-mapping/src/evm/opcodes/error_oog_exp.rs @@ -0,0 +1,36 @@ +use super::{Opcode, OpcodeId}; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + error::{ExecError, OogError}, + Error, +}; +use eth_types::GethExecStep; + +/// Placeholder structure used to implement [`Opcode`] trait over it +/// corresponding to the [`OogError::Exp`](crate::error::OogError::Exp). +#[derive(Clone, Copy, Debug)] +pub(crate) struct OOGExp; + +impl Opcode for OOGExp { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + debug_assert_eq!(geth_step.op, OpcodeId::EXP); + + let mut exec_step = state.new_step(geth_step)?; + exec_step.error = Some(ExecError::OutOfGas(OogError::Exp)); + + for i in 0..2 { + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(i), + geth_step.stack.nth_last(i)?, + )?; + } + + state.handle_return(&mut exec_step, geth_steps, true)?; + Ok(vec![exec_step]) + } +} diff --git a/bus-mapping/src/evm/opcodes/error_oog_log.rs b/bus-mapping/src/evm/opcodes/error_oog_log.rs new file mode 100644 index 0000000000..cad2fcfa9e --- /dev/null +++ b/bus-mapping/src/evm/opcodes/error_oog_log.rs @@ -0,0 +1,50 @@ +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + evm::{Opcode, OpcodeId}, + operation::CallContextField, + Error, +}; +use eth_types::{GethExecStep, Word}; + +#[derive(Debug, Copy, Clone)] +pub(crate) struct ErrorOOGLog; + +impl Opcode for ErrorOOGLog { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + let mut exec_step = state.new_step(geth_step)?; + let next_step = if geth_steps.len() > 1 { + Some(&geth_steps[1]) + } else { + None + }; + exec_step.error = state.get_step_err(geth_step, next_step)?; + // assert op code can only be Log* + assert!([ + OpcodeId::LOG0, + OpcodeId::LOG1, + OpcodeId::LOG2, + OpcodeId::LOG3, + OpcodeId::LOG4 + ] + .contains(&geth_step.op)); + let mstart = geth_step.stack.nth_last(0)?; + let msize = geth_step.stack.nth_last(1)?; + + state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(0), mstart)?; + state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(1), msize)?; + // read static call property + state.call_context_read( + &mut exec_step, + state.call()?.call_id, + CallContextField::IsStatic, + Word::from(state.call()?.is_static as u8), + ); + + state.handle_return(&mut exec_step, geth_steps, true)?; + Ok(vec![exec_step]) + } +} diff --git a/bus-mapping/src/evm/opcodes/error_oog_memory_copy.rs b/bus-mapping/src/evm/opcodes/error_oog_memory_copy.rs new file mode 100644 index 0000000000..b334414231 --- /dev/null +++ b/bus-mapping/src/evm/opcodes/error_oog_memory_copy.rs @@ -0,0 +1,73 @@ +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + error::{ExecError, OogError}, + evm::Opcode, + operation::{CallContextField, TxAccessListAccountOp, RW}, + Error, +}; +use eth_types::{evm_types::OpcodeId, GethExecStep, ToAddress}; + +/// Placeholder structure used to implement [`Opcode`] trait over it +/// corresponding to the +/// [`OogError::MemoryCopy`](crate::error::OogError::MemoryCopy). +#[derive(Clone, Copy, Debug)] +pub(crate) struct OOGMemoryCopy; + +impl Opcode for OOGMemoryCopy { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + debug_assert!([ + OpcodeId::CALLDATACOPY, + OpcodeId::CODECOPY, + OpcodeId::EXTCODECOPY, + OpcodeId::RETURNDATACOPY + ] + .contains(&geth_step.op)); + + let mut exec_step = state.new_step(geth_step)?; + exec_step.error = Some(ExecError::OutOfGas(OogError::MemoryCopy)); + + let is_extcodecopy = geth_step.op == OpcodeId::EXTCODECOPY; + + // According to EIP-2929, EXTCODECOPY constant gas cost is different for cold + // and warm accounts. + if is_extcodecopy { + state.call_context_read( + &mut exec_step, + state.call()?.call_id, + CallContextField::TxId, + state.tx_ctx.id().into(), + ); + + let external_address = geth_step.stack.last()?.to_address(); + let is_warm = state.sdb.check_account_in_access_list(&external_address); + state.push_op( + &mut exec_step, + RW::READ, + TxAccessListAccountOp { + tx_id: state.tx_ctx.id(), + address: external_address, + is_warm, + is_warm_prev: is_warm, + }, + ); + } + + // Each of CALLDATACOPY, CODECOPY and RETURNDATACOPY has 3 stack read values. + // But EXTCODECOPY has 4. It has an extra stack pop for external address. + let stack_read_num = if is_extcodecopy { 4 } else { 3 }; + for i in 0..stack_read_num { + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(i), + geth_step.stack.nth_last(i)?, + )?; + } + + state.handle_return(&mut exec_step, geth_steps, true)?; + Ok(vec![exec_step]) + } +} diff --git a/bus-mapping/src/evm/opcodes/error_oog_sload_sstore.rs b/bus-mapping/src/evm/opcodes/error_oog_sload_sstore.rs new file mode 100644 index 0000000000..6fbb24b83a --- /dev/null +++ b/bus-mapping/src/evm/opcodes/error_oog_sload_sstore.rs @@ -0,0 +1,95 @@ +use super::{Opcode, OpcodeId}; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + error::{ExecError, OogError}, + operation::{CallContextField, StorageOp, TxAccessListAccountStorageOp, RW}, + Error, +}; +use eth_types::{GethExecStep, ToWord}; + +/// Placeholder structure used to implement [`Opcode`] trait over it +/// corresponding to the +/// [`OogError::SloadSstore`](crate::error::OogError::SloadSstore). +#[derive(Clone, Copy, Debug)] +pub(crate) struct OOGSloadSstore; + +impl Opcode for OOGSloadSstore { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + debug_assert!([OpcodeId::SLOAD, OpcodeId::SSTORE].contains(&geth_step.op)); + + let mut exec_step = state.new_step(geth_step)?; + exec_step.error = Some(ExecError::OutOfGas(OogError::SloadSstore)); + + let call_id = state.call()?.call_id; + let callee_address = state.call()?.address; + let tx_id = state.tx_ctx.id(); + + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::TxId, + tx_id.into(), + ); + + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::IsStatic, + (state.call()?.is_static as u8).into(), + ); + + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::CalleeAddress, + callee_address.to_word(), + ); + + let key = geth_step.stack.last()?; + state.stack_read(&mut exec_step, geth_step.stack.last_filled(), key)?; + + let is_warm = state + .sdb + .check_account_storage_in_access_list(&(callee_address, key)); + state.push_op( + &mut exec_step, + RW::READ, + TxAccessListAccountStorageOp { + tx_id, + address: callee_address, + key, + is_warm, + is_warm_prev: is_warm, + }, + ); + + // Special operations are only used for SSTORE. + if geth_step.op == OpcodeId::SSTORE { + let value = geth_step.stack.nth_last(1)?; + state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(1), value)?; + + let (_, value_prev) = state.sdb.get_storage(&callee_address, &key); + let (_, original_value) = state.sdb.get_committed_storage(&callee_address, &key); + + state.push_op( + &mut exec_step, + RW::READ, + StorageOp::new( + callee_address, + key, + *value_prev, + *value_prev, + tx_id, + *original_value, + ), + ); + } + + state.handle_return(&mut exec_step, geth_steps, true)?; + Ok(vec![exec_step]) + } +} diff --git a/bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs b/bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs new file mode 100644 index 0000000000..e2479924d5 --- /dev/null +++ b/bus-mapping/src/evm/opcodes/error_return_data_outofbound.rs @@ -0,0 +1,146 @@ +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + error::ExecError, + evm::Opcode, + operation::CallContextField, + Error, +}; +use eth_types::{GethExecStep, Word}; + +#[derive(Debug, Copy, Clone)] +pub(crate) struct ErrorReturnDataOutOfBound; + +impl Opcode for ErrorReturnDataOutOfBound { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + let mut exec_step = state.new_step(geth_step)?; + let next_step = geth_steps.get(1); + + exec_step.error = Some(ExecError::ReturnDataOutOfBounds); + assert_eq!( + state.get_step_err(geth_step, next_step).unwrap(), + Some(ExecError::ReturnDataOutOfBounds) + ); + + let memory_offset = geth_step.stack.nth_last(0)?; + let data_offset = geth_step.stack.nth_last(1)?; + let length = geth_step.stack.nth_last(2)?; + + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(0), + memory_offset, + )?; + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(1), + data_offset, + )?; + state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(2), length)?; + + let call_id = state.call()?.call_id; + let call_ctx = state.call_ctx()?; + let return_data = &call_ctx.return_data; + let last_callee_return_data_length = state.call()?.last_callee_return_data_length; + assert_eq!( + last_callee_return_data_length as usize, + return_data.len(), + "callee return data size should be correct" + ); + + let remainder_end = data_offset.overflowing_add(length).0; + // check data_offset or end is u64 overflow, or + // last_callee_return_data_length < reaminder_end + let data_offset_overflow = data_offset > Word::from(u64::MAX); + let remainder_end_overflow = remainder_end > Word::from(u64::MAX); + let remainder_end_exceed_length = + Word::from(last_callee_return_data_length) < remainder_end; + // one of three must hold at least one. + assert!(data_offset_overflow | remainder_end_overflow | remainder_end_exceed_length); + // read last callee info + state.call_context_read( + &mut exec_step, + call_id, + CallContextField::LastCalleeReturnDataLength, + return_data.len().into(), + ); + + // `IsSuccess` call context operation is added in handle_return + state.handle_return(&mut exec_step, geth_steps, true)?; + Ok(vec![exec_step]) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{circuit_input_builder::ExecState, mock::BlockData, operation::RW}; + use eth_types::{bytecode, evm_types::OpcodeId, geth_types::GethData}; + use mock::{ + test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, + TestContext, MOCK_DEPLOYED_CONTRACT_BYTECODE, + }; + + #[test] + fn test_returndata_error() { + let code = bytecode! { + PUSH21(*MOCK_DEPLOYED_CONTRACT_BYTECODE) + PUSH1(0) + MSTORE + + PUSH1 (0x15) // size + PUSH1 (0xB) // offset + PUSH1 (0) // value + CREATE + + PUSH1 (0x20) // retLength + PUSH1 (0x20) // retOffset + PUSH1 (0x20) // argsLength + PUSH1 (0) // argsOffset + PUSH1 (0) // value + DUP6 // addr from above CREATE + PUSH2 (0xFFFF) // gas + CALL + + PUSH1 (0x40) // 0x40 > 0x20 (which return from above CALL), result in ReturnDataOutOfBounds + PUSH1 (0) + PUSH1 (0x40) + RETURNDATACOPY + + STOP + }; + + // Get the execution steps from the external tracer + let block: GethData = TestContext::<2, 1>::new( + None, + account_0_code_account_1_no_code(code), + tx_from_1_to_0, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap() + .into(); + + let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + + let tx_id = 1; + let transaction = &builder.block.txs()[tx_id - 1]; + let step = transaction + .steps() + .iter() + .filter(|step| step.exec_state == ExecState::Op(OpcodeId::RETURNDATACOPY)) + .last() + .unwrap(); + + assert_eq!(step.error, Some(ExecError::ReturnDataOutOfBounds)); + + let container = builder.block.container.clone(); + let operation = &container.stack[step.bus_mapping_instance[0].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + } +} diff --git a/bus-mapping/src/evm/opcodes/error_simple.rs b/bus-mapping/src/evm/opcodes/error_simple.rs new file mode 100644 index 0000000000..c27dd06e33 --- /dev/null +++ b/bus-mapping/src/evm/opcodes/error_simple.rs @@ -0,0 +1,28 @@ +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + evm::Opcode, + Error, +}; +use eth_types::GethExecStep; + +#[derive(Debug, Copy, Clone)] +pub(crate) struct ErrorSimple; + +// ErrorSimple is to deal with errors with general common ops as below +// - added error to current `ExecStep` +// - restore call context +// no extra ops e.g. stack read etc... +impl Opcode for ErrorSimple { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + let mut exec_step = state.new_step(geth_step)?; + let next_step = geth_steps.get(1); + exec_step.error = state.get_step_err(geth_step, next_step).unwrap(); + + state.handle_return(&mut exec_step, geth_steps, true)?; + Ok(vec![exec_step]) + } +} diff --git a/bus-mapping/src/evm/opcodes/error_write_protection.rs b/bus-mapping/src/evm/opcodes/error_write_protection.rs new file mode 100644 index 0000000000..58c4f937de --- /dev/null +++ b/bus-mapping/src/evm/opcodes/error_write_protection.rs @@ -0,0 +1,69 @@ +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + error::ExecError, + evm::{Opcode, OpcodeId}, + operation::CallContextField, + Error, +}; + +use eth_types::GethExecStep; + +#[derive(Debug, Copy, Clone)] +pub(crate) struct ErrorWriteProtection; + +impl Opcode for ErrorWriteProtection { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + let mut exec_step = state.new_step(geth_step)?; + let next_step = if geth_steps.len() > 1 { + Some(&geth_steps[1]) + } else { + None + }; + exec_step.error = state.get_step_err(geth_step, next_step).unwrap(); + // assert error is targeting ExecError::WriteProtection. + assert_eq!(exec_step.clone().error.unwrap(), ExecError::WriteProtection); + + let current_call = state.call()?.clone(); + // assert op code can only be following codes + assert!([ + OpcodeId::SSTORE, + OpcodeId::CREATE, + OpcodeId::CREATE2, + OpcodeId::CALL, + OpcodeId::SELFDESTRUCT, + OpcodeId::LOG0, + OpcodeId::LOG1, + OpcodeId::LOG2, + OpcodeId::LOG3, + OpcodeId::LOG4 + ] + .contains(&geth_step.op)); + + if geth_step.op == OpcodeId::CALL { + // get only the frist three stack elements since the third one is the value we + // want to check. + for i in 0..3 { + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(i), + geth_step.stack.nth_last(i)?, + )?; + } + } + + state.call_context_read( + &mut exec_step, + current_call.call_id, + CallContextField::IsStatic, + (current_call.is_static as u64).into(), + ); + + // `IsSuccess` call context operation is added in handle_return + state.handle_return(&mut exec_step, geth_steps, true)?; + Ok(vec![exec_step]) + } +} diff --git a/bus-mapping/src/evm/opcodes/exp.rs b/bus-mapping/src/evm/opcodes/exp.rs new file mode 100644 index 0000000000..e44a1fadf6 --- /dev/null +++ b/bus-mapping/src/evm/opcodes/exp.rs @@ -0,0 +1,103 @@ +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep, ExpEvent, ExpStep}, + Error, +}; +use eth_types::{GethExecStep, U256}; + +use super::Opcode; + +#[derive(Clone, Copy, Debug)] +pub(crate) struct Exponentiation; + +fn exp_by_squaring(base: U256, exponent: U256, steps: &mut Vec) -> U256 { + if exponent.is_zero() { + return U256::one(); + } + if exponent == U256::one() { + return base; + } + + let (exponent_div2, odd) = exponent.div_mod(U256::from(2)); + let exp1 = exp_by_squaring(base, exponent_div2, steps); + let (exp2, _) = exp1.overflowing_mul(exp1); + steps.push((exp1, exp1, exp2).into()); + + if odd.is_zero() { + // exponent is even + exp2 + } else { + // exponent is odd + let (exp, _) = base.overflowing_mul(exp2); + steps.push((exp2, base, exp).into()); + exp + } +} + +impl Opcode for Exponentiation { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + let mut exec_step = state.new_step(geth_step)?; + + let base = geth_step.stack.nth_last(0)?; + state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(0), base)?; + let exponent = geth_step.stack.nth_last(1)?; + state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(1), exponent)?; + + let (exponentiation, _) = base.overflowing_pow(exponent); + state.stack_write( + &mut exec_step, + geth_steps[1].stack.last_filled(), + exponentiation, + )?; + + let mut steps = Vec::new(); + let exponentiation_calc = exp_by_squaring(base, exponent, &mut steps); + debug_assert_eq!(exponentiation, exponentiation_calc); + state.push_exponentiation(ExpEvent { + identifier: state.block_ctx.rwc.0, + base, + exponent, + exponentiation, + steps, + }); + + Ok(vec![exec_step]) + } +} + +#[cfg(test)] +mod tests { + use eth_types::U256; + + use super::exp_by_squaring; + + #[test] + fn test_exp_by_squaring() { + let mut steps = Vec::new(); + let exp = exp_by_squaring(23u64.into(), 123u64.into(), &mut steps); + assert_eq!( + exp, + U256::from_dec_str( + "87180413255890732361416772728849128389641993872302935967571352892955279939527" + ) + .unwrap() + ); + + let mut steps = Vec::new(); + let exp = exp_by_squaring(3u64.into(), 13u64.into(), &mut steps); + assert_eq!(exp, 1594323u64.into()); + assert_eq!( + steps, + vec![ + (3.into(), 3.into(), 9.into()).into(), + (9.into(), 3.into(), 27.into()).into(), + (27.into(), 27.into(), 729.into()).into(), + (729.into(), 729.into(), 531441.into()).into(), + (531441.into(), 3.into(), 1594323.into()).into(), + ] + ); + } +} diff --git a/bus-mapping/src/evm/opcodes/extcodecopy.rs b/bus-mapping/src/evm/opcodes/extcodecopy.rs index 2b92485211..108f5f0d08 100644 --- a/bus-mapping/src/evm/opcodes/extcodecopy.rs +++ b/bus-mapping/src/evm/opcodes/extcodecopy.rs @@ -1,8 +1,12 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::operation::{TxAccessListAccountOp, RW}; -use crate::Error; -use eth_types::{GethExecStep, ToAddress}; +use crate::{ + circuit_input_builder::{ + CircuitInputStateRef, CopyDataType, CopyEvent, ExecStep, NumberOrHash, + }, + operation::{AccountField, CallContextField, TxAccessListAccountOp}, + Error, +}; +use eth_types::{Bytecode, GethExecStep, ToAddress, ToWord, H256, U256}; #[derive(Clone, Copy, Debug)] pub(crate) struct Extcodecopy; @@ -13,39 +17,25 @@ impl Opcode for Extcodecopy { geth_steps: &[GethExecStep], ) -> Result, Error> { let geth_step = &geth_steps[0]; - let exec_steps = vec![gen_extcodecopy_step(state, geth_step)?]; + let mut exec_steps = vec![gen_extcodecopy_step(state, geth_step)?]; // reconstruction let address = geth_steps[0].stack.nth_last(0)?.to_address(); - let dest_offset = geth_steps[0].stack.nth_last(1)?.as_u64(); - let code_offset = geth_steps[0].stack.nth_last(2)?.as_u64(); - let length = geth_steps[0].stack.nth_last(3)?.as_u64(); + let dst_offset = geth_steps[0].stack.nth_last(1)?; + let code_offset = geth_step.stack.nth_last(2)?; + let length = geth_steps[0].stack.nth_last(3)?; - let (exist, account) = state.sdb.get_account(&address); - assert!(exist, "target account does not exist"); - let code = state.code(account.code_hash)?; + let (_, account) = state.sdb.get_account(&address); + let code_hash = account.code_hash; + let code = state.code(code_hash)?; let call_ctx = state.call_ctx_mut()?; let memory = &mut call_ctx.memory; - if length != 0 { - let minimal_length = (dest_offset + length) as usize; - memory.extend_at_least(minimal_length); - - let mem_starts = dest_offset as usize; - let mem_ends = mem_starts + length as usize; - let code_starts = code_offset as usize; - let code_ends = code_starts + length as usize; - if code_ends <= code.len() { - memory[mem_starts..mem_ends].copy_from_slice(&code[code_starts..code_ends]); - } else if let Some(actual_length) = code.len().checked_sub(code_starts) { - let mem_code_ends = mem_starts + actual_length; - memory[mem_starts..mem_code_ends].copy_from_slice(&code[code_starts..]); - // since we already resize the memory, no need to copy 0s for - // out of bound bytes - } - } - // TODO: implement copy event + memory.copy_from(dst_offset, code_offset, length, &code); + + let copy_event = gen_copy_event(state, geth_step)?; + state.push_copy(&mut exec_steps[0], copy_event); Ok(exec_steps) } } @@ -56,90 +46,196 @@ fn gen_extcodecopy_step( ) -> Result { let mut exec_step = state.new_step(geth_step)?; - let address = geth_step.stack.nth_last(0)?; + let external_address_word = geth_step.stack.nth_last(0)?; + let external_address = external_address_word.to_address(); let dest_offset = geth_step.stack.nth_last(1)?; let offset = geth_step.stack.nth_last(2)?; let length = geth_step.stack.nth_last(3)?; - let is_warm = state - .sdb - .check_account_in_access_list(&address.to_address()); + // stack reads + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(0), + external_address_word, + )?; + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(1), + dest_offset, + )?; + state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(2), offset)?; + state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(3), length)?; + + for (field, value) in [ + (CallContextField::TxId, U256::from(state.tx_ctx.id())), + ( + CallContextField::RwCounterEndOfReversion, + U256::from(state.call()?.rw_counter_end_of_reversion as u64), + ), + ( + CallContextField::IsPersistent, + U256::from(state.call()?.is_persistent as u64), + ), + ] { + state.call_context_read(&mut exec_step, state.call()?.call_id, field, value); + } + + let is_warm = state.sdb.check_account_in_access_list(&external_address); state.push_op_reversible( &mut exec_step, - RW::WRITE, TxAccessListAccountOp { tx_id: state.tx_ctx.id(), - address: address.to_address(), + address: external_address, is_warm: true, is_warm_prev: is_warm, }, )?; - // stack reads - state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(0), address)?; - state.stack_read( + let account = state.sdb.get_account(&external_address).1; + let exists = !account.is_empty(); + let code_hash = if exists { + account.code_hash + } else { + H256::zero() + }; + + state.account_read( &mut exec_step, - geth_step.stack.nth_last_filled(1), - dest_offset, - )?; - state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(2), offset)?; - state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(3), length)?; + external_address, + AccountField::CodeHash, + code_hash.to_word(), + ); Ok(exec_step) } +fn gen_copy_event( + state: &mut CircuitInputStateRef, + geth_step: &GethExecStep, +) -> Result { + let rw_counter_start = state.block_ctx.rwc; + + let external_address = geth_step.stack.nth_last(0)?.to_address(); + let dst_offset = geth_step.stack.nth_last(1)?; + let code_offset = geth_step.stack.nth_last(2)?; + let length = geth_step.stack.nth_last(3)?.as_u64(); + + let account = state.sdb.get_account(&external_address).1; + let exists = !account.is_empty(); + let code_hash = if exists { + account.code_hash + } else { + H256::zero() + }; + + let bytecode: Bytecode = if exists { + state.code(code_hash)?.into() + } else { + Bytecode::default() + }; + let code_size = bytecode.code.len() as u64; + + // Get low Uint64 of offset to generate copy steps. Since offset could be + // Uint64 overflow if length is zero. + let dst_addr = dst_offset.low_u64(); + let src_addr_end = code_size; + + // Reset start offset to end offset if overflow. + let src_addr = u64::try_from(code_offset) + .unwrap_or(src_addr_end) + .min(src_addr_end); + + let mut exec_step = state.new_step(geth_step)?; + let copy_steps = state.gen_copy_steps_for_bytecode( + &mut exec_step, + &bytecode, + src_addr, + dst_addr, + src_addr_end, + length, + )?; + + Ok(CopyEvent { + src_addr, + src_addr_end, + src_type: CopyDataType::Bytecode, + src_id: NumberOrHash::Hash(code_hash), + dst_addr, + dst_type: CopyDataType::Memory, + dst_id: NumberOrHash::Number(state.call()?.call_id), + log_id: None, + rw_counter_start, + bytes: copy_steps, + }) +} + #[cfg(test)] mod extcodecopy_tests { - use crate::mock::BlockData; - use eth_types::geth_types::GethData; - use eth_types::{bytecode, word}; - use mock::test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}; + use crate::{ + circuit_input_builder::{CopyDataType, ExecState, NumberOrHash}, + mock::BlockData, + operation::{ + AccountField, AccountOp, CallContextField, CallContextOp, MemoryOp, StackOp, + TxAccessListAccountOp, RW, + }, + state_db::CodeDB, + }; + use eth_types::{ + address, bytecode, + evm_types::{MemoryAddress, OpcodeId, StackAddress}, + geth_types::GethData, + Bytecode, Bytes, ToWord, Word, U256, + }; use mock::TestContext; - #[test] - fn test_ok() { - // // deployed contract - // PUSH1 0x20 - // PUSH1 0 - // PUSH1 0 - // CALLDATACOPY - // PUSH1 0x20 - // PUSH1 0 - // RETURN - // - // bytecode: 0x6020600060003760206000F3 - // - // // constructor - // PUSH12 0x6020600060003760206000F3 - // PUSH1 0 - // MSTORE - // PUSH1 0xC - // PUSH1 0x14 - // RETURN - // - // bytecode: 0x6B6020600060003760206000F3600052600C6014F3 - let code = bytecode! { - PUSH21(word!("6B6020600060003760206000F3600052600C6014F3")) - PUSH1(0) - MSTORE - - PUSH1 (0x15) - PUSH1 (0xB) - PUSH1 (0) - CREATE - - PUSH1 (0x20) - PUSH1 (0x0) - PUSH1 (0x20) - DUP4 + fn test_ok( + code_ext: Bytes, + is_warm: bool, + data_offset: usize, + memory_offset: usize, + copy_size: usize, + ) { + let external_address = address!("0xaabbccddee000000000000000000000000000000"); + let mut code = Bytecode::default(); + if is_warm { + code.append(&bytecode! { + PUSH20(external_address.to_word()) + EXTCODEHASH + POP + }) + } + code.append(&bytecode! { + PUSH32 (copy_size) + PUSH32 (data_offset) + PUSH32 (memory_offset) + PUSH20 (external_address.to_word()) EXTCODECOPY - STOP + }); + + let bytecode_ext = Bytecode::from(code_ext.to_vec()); + let code_hash = if code_ext.is_empty() { + Default::default() + } else { + CodeDB::hash(&code_ext) }; + // Get the execution steps from the external tracer - let block: GethData = TestContext::<2, 1>::new( + let block: GethData = TestContext::<3, 1>::new( None, - account_0_code_account_1_no_code(code), - tx_from_1_to_0, + |accs| { + accs[0] + .address(address!("0x0000000000000000000000000000000000000010")) + .code(code.clone()); + + accs[1].address(external_address).code(code_ext.clone()); + + accs[2] + .address(address!("0x0000000000000000000000000000000000cafe01")) + .balance(Word::from(1u64 << 20)); + }, + |mut txs, accs| { + txs[0].to(accs[0].address).from(accs[2].address); + }, |block, _tx| block.number(0xcafeu64), ) .unwrap() @@ -149,5 +245,221 @@ mod extcodecopy_tests { builder .handle_block(&block.eth_block, &block.geth_traces) .unwrap(); + + assert!(builder.sdb.add_account_to_access_list(external_address)); + + let tx_id = 1; + let transaction = &builder.block.txs()[tx_id - 1]; + let call_id = transaction.calls()[0].call_id; + + let indices = transaction + .steps() + .iter() + .filter(|step| step.exec_state == ExecState::Op(OpcodeId::EXTCODECOPY)) + .last() + .unwrap() + .bus_mapping_instance + .clone(); + let container = &builder.block.container; + assert_eq!( + { + let operation = &container.stack[indices[0].as_usize()]; + (operation.rw(), operation.op()) + }, + ( + RW::READ, + &StackOp { + call_id, + address: StackAddress::from(1020u32), + value: external_address.to_word() + } + ) + ); + assert_eq!( + { + let operation = &container.stack[indices[1].as_usize()]; + (operation.rw(), operation.op()) + }, + ( + RW::READ, + &StackOp { + call_id, + address: StackAddress::from(1021u32), + value: memory_offset.into() + } + ) + ); + assert_eq!( + { + let operation = &container.stack[indices[2].as_usize()]; + (operation.rw(), operation.op()) + }, + ( + RW::READ, + &StackOp { + call_id, + address: StackAddress::from(1022u32), + value: data_offset.into() + } + ) + ); + assert_eq!( + { + let operation = &container.stack[indices[3].as_usize()]; + (operation.rw(), operation.op()) + }, + ( + RW::READ, + &StackOp { + call_id, + address: StackAddress::from(1023u32), + value: copy_size.into() + } + ) + ); + assert_eq!( + { + let operation = &container.call_context[indices[4].as_usize()]; + (operation.rw(), operation.op()) + }, + ( + RW::READ, + &CallContextOp { + call_id, + field: CallContextField::TxId, + value: tx_id.into() + } + ) + ); + assert_eq!( + { + let operation = &container.call_context[indices[5].as_usize()]; + (operation.rw(), operation.op()) + }, + ( + RW::READ, + &CallContextOp { + call_id, + field: CallContextField::RwCounterEndOfReversion, + value: U256::zero() + } + ) + ); + assert_eq!( + { + let operation = &container.call_context[indices[6].as_usize()]; + (operation.rw(), operation.op()) + }, + ( + RW::READ, + &CallContextOp { + call_id, + field: CallContextField::IsPersistent, + value: U256::one() + } + ) + ); + assert_eq!( + { + let operation = &container.tx_access_list_account[indices[7].as_usize()]; + (operation.rw(), operation.op()) + }, + ( + RW::WRITE, + &TxAccessListAccountOp { + tx_id, + address: external_address, + is_warm: true, + is_warm_prev: is_warm + } + ) + ); + assert_eq!( + { + let operation = &container.account[indices[8].as_usize()]; + (operation.rw(), operation.op()) + }, + ( + RW::READ, + &AccountOp { + address: external_address, + field: AccountField::CodeHash, + value: code_hash.to_word(), + value_prev: code_hash.to_word(), + } + ) + ); + + let step = transaction + .steps() + .iter() + .find(|step| step.exec_state == ExecState::Op(OpcodeId::EXTCODECOPY)) + .unwrap(); + + let expected_call_id = transaction.calls()[step.call_index].call_id; + + assert_eq!( + (0..copy_size) + .map(|idx| &builder.block.container.memory[idx]) + .map(|op| (op.rw(), op.op().clone())) + .collect::>(), + (0..copy_size) + .map(|idx| { + ( + RW::WRITE, + MemoryOp::new( + expected_call_id, + MemoryAddress::from(memory_offset + idx), + if data_offset + idx < bytecode_ext.to_vec().len() { + bytecode_ext.to_vec()[data_offset + idx] + } else { + 0 + }, + ), + ) + }) + .collect::>(), + ); + + let copy_events = builder.block.copy_events.clone(); + assert_eq!(copy_events.len(), 1); + assert_eq!(copy_events[0].bytes.len(), copy_size); + assert_eq!(copy_events[0].src_id, NumberOrHash::Hash(code_hash)); + assert_eq!(copy_events[0].src_addr as usize, data_offset); + assert_eq!(copy_events[0].src_addr_end as usize, code_ext.len()); + assert_eq!(copy_events[0].src_type, CopyDataType::Bytecode); + assert_eq!( + copy_events[0].dst_id, + NumberOrHash::Number(expected_call_id) + ); + assert_eq!(copy_events[0].dst_addr as usize, memory_offset); + assert_eq!(copy_events[0].dst_type, CopyDataType::Memory); + assert!(copy_events[0].log_id.is_none()); + + for (idx, (value, is_code)) in copy_events[0].bytes.iter().enumerate() { + let bytecode_element = bytecode_ext.get(idx).unwrap_or_default(); + assert_eq!(*value, bytecode_element.value); + assert_eq!(*is_code, bytecode_element.is_code); + } + } + + #[test] + fn cold_empty_account() { + test_ok(Bytes::from([]), false, 0x0usize, 0x0usize, 0x30usize); + } + + #[test] + fn warm_empty_account() { + test_ok(Bytes::from([]), true, 0x0usize, 0x0usize, 0x30usize); + } + + #[test] + fn cold_non_empty_account() { + test_ok(Bytes::from([10, 40]), false, 0x0usize, 0x0usize, 0x30usize); + } + + #[test] + fn warm_non_empty_account() { + test_ok(Bytes::from([10, 40]), true, 0x0usize, 0x0usize, 0x30usize); } } diff --git a/bus-mapping/src/evm/opcodes/extcodehash.rs b/bus-mapping/src/evm/opcodes/extcodehash.rs index 24e37dbe45..7b6bc9e24f 100644 --- a/bus-mapping/src/evm/opcodes/extcodehash.rs +++ b/bus-mapping/src/evm/opcodes/extcodehash.rs @@ -2,11 +2,10 @@ use super::Opcode; use crate::{ circuit_input_builder::CircuitInputStateRef, evm::opcodes::ExecStep, - operation::{AccountField, CallContextField, TxAccessListAccountOp, RW}, - state_db::Account, + operation::{AccountField, CallContextField, TxAccessListAccountOp}, Error, }; -use eth_types::{GethExecStep, ToAddress, ToWord, U256}; +use eth_types::{GethExecStep, ToAddress, ToWord, H256, U256}; #[derive(Debug, Copy, Clone)] pub(crate) struct Extcodehash; @@ -21,8 +20,9 @@ impl Opcode for Extcodehash { let stack_address = step.stack.last_filled(); // Pop external address off stack - let external_address = step.stack.last()?.to_address(); - state.stack_read(&mut exec_step, stack_address, external_address.to_word())?; + let external_address_word = step.stack.last()?; + let external_address = external_address_word.to_address(); + state.stack_read(&mut exec_step, stack_address, external_address_word)?; // Read transaction id, rw_counter_end_of_reversion, and is_persistent from call // context @@ -45,7 +45,6 @@ impl Opcode for Extcodehash { let is_warm = state.sdb.check_account_in_access_list(&external_address); state.push_op_reversible( &mut exec_step, - RW::WRITE, TxAccessListAccountOp { tx_id: state.tx_ctx.id(), address: external_address, @@ -54,37 +53,19 @@ impl Opcode for Extcodehash { }, )?; - // These three lookups are required to determine the existence of the external - // account - let &Account { - nonce, - code_hash, - balance, - .. - } = state.sdb.get_account(&external_address).1; - state.account_read( - &mut exec_step, - external_address, - AccountField::Nonce, - nonce, - nonce, - )?; - - state.account_read( - &mut exec_step, - external_address, - AccountField::Balance, - balance, - balance, - )?; - + let account = state.sdb.get_account(&external_address).1; + let exists = !account.is_empty(); + let code_hash = if exists { + account.code_hash + } else { + H256::zero() + }; state.account_read( &mut exec_step, external_address, AccountField::CodeHash, code_hash.to_word(), - code_hash.to_word(), - )?; + ); // Stack write of the result of EXTCODEHASH. state.stack_write(&mut exec_step, stack_address, steps[1].stack.last()?)?; @@ -96,16 +77,18 @@ impl Opcode for Extcodehash { #[cfg(test)] mod extcodehash_tests { use super::*; - use crate::circuit_input_builder::ExecState; - use crate::mock::BlockData; - use crate::operation::{AccountOp, CallContextOp, StackOp}; + use crate::{ + circuit_input_builder::ExecState, + mock::BlockData, + operation::{AccountOp, CallContextOp, StackOp, RW}, + state_db::CodeDB, + }; use eth_types::{ address, bytecode, evm_types::{OpcodeId, StackAddress}, geth_types::GethData, Bytecode, Bytes, Word, U256, }; - use ethers_core::utils::keccak256; use mock::TestContext; use pretty_assertions::assert_eq; @@ -147,12 +130,12 @@ mod extcodehash_tests { EXTCODEHASH STOP }); - let mut nonce = Word::from(300u64); + let mut nonce = 300u64; let mut balance = Word::from(800u64); let mut code_ext = Bytes::from([34, 54, 56]); if !exists { - nonce = Word::zero(); + nonce = 0; balance = Word::zero(); code_ext = Bytes::default(); } @@ -184,7 +167,7 @@ mod extcodehash_tests { .unwrap() .into(); - let code_hash = Word::from(keccak256(code_ext)); + let code_hash = CodeDB::hash(&code_ext).to_word(); let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); builder @@ -283,49 +266,19 @@ mod extcodehash_tests { let operation = &container.account[indices[5].as_usize()]; (operation.rw(), operation.op()) }, - ( - RW::READ, - &AccountOp { - address: external_address, - field: AccountField::Nonce, - value: if exists { nonce } else { U256::zero() }, - value_prev: if exists { nonce } else { U256::zero() }, - } - ) - ); - assert_eq!( - { - let operation = &container.account[indices[6].as_usize()]; - (operation.rw(), operation.op()) - }, - ( - RW::READ, - &AccountOp { - address: external_address, - field: AccountField::Balance, - value: if exists { balance } else { U256::zero() }, - value_prev: if exists { balance } else { U256::zero() }, - } - ) - ); - assert_eq!( - { - let operation = &container.account[indices[7].as_usize()]; - (operation.rw(), operation.op()) - }, ( RW::READ, &AccountOp { address: external_address, field: AccountField::CodeHash, - value: code_hash, - value_prev: code_hash, + value: if exists { code_hash } else { U256::zero() }, + value_prev: if exists { code_hash } else { U256::zero() }, } ) ); assert_eq!( { - let operation = &container.stack[indices[8].as_usize()]; + let operation = &container.stack[indices[6].as_usize()]; (operation.rw(), operation.op()) }, ( diff --git a/bus-mapping/src/evm/opcodes/extcodesize.rs b/bus-mapping/src/evm/opcodes/extcodesize.rs index e7219ae71c..440e6607e2 100644 --- a/bus-mapping/src/evm/opcodes/extcodesize.rs +++ b/bus-mapping/src/evm/opcodes/extcodesize.rs @@ -1,8 +1,10 @@ -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::evm::Opcode; -use crate::operation::{TxAccessListAccountOp, RW}; -use crate::Error; -use eth_types::{GethExecStep, ToAddress, ToWord}; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + evm::Opcode, + operation::{AccountField, CallContextField, TxAccessListAccountOp}, + Error, +}; +use eth_types::{GethExecStep, ToAddress, ToWord, H256}; #[derive(Debug, Copy, Clone)] pub(crate) struct Extcodesize; @@ -12,34 +14,247 @@ impl Opcode for Extcodesize { state: &mut CircuitInputStateRef, geth_steps: &[GethExecStep], ) -> Result, Error> { - // TODO: finish this, only access list part is done let geth_step = &geth_steps[0]; let mut exec_step = state.new_step(geth_step)?; - let external_address = geth_steps[0].stack.last()?.to_address(); - state.stack_read( - &mut exec_step, - geth_step.stack.last_filled(), - external_address.to_word(), - )?; - let is_warm = state.sdb.check_account_in_access_list(&external_address); + // Read account address from stack. + let address_word = geth_step.stack.last()?; + let address = address_word.to_address(); + state.stack_read(&mut exec_step, geth_step.stack.last_filled(), address_word)?; + + // Read transaction ID, rw_counter_end_of_reversion, and is_persistent from call + // context. + for (field, value) in [ + (CallContextField::TxId, state.tx_ctx.id().to_word()), + ( + CallContextField::RwCounterEndOfReversion, + state.call()?.rw_counter_end_of_reversion.to_word(), + ), + ( + CallContextField::IsPersistent, + state.call()?.is_persistent.to_word(), + ), + ] { + state.call_context_read(&mut exec_step, state.call()?.call_id, field, value); + } + + // Update transaction access list for account address. + let is_warm = state.sdb.check_account_in_access_list(&address); state.push_op_reversible( &mut exec_step, - RW::WRITE, TxAccessListAccountOp { tx_id: state.tx_ctx.id(), - address: external_address, + address, is_warm: true, is_warm_prev: is_warm, }, )?; + // Read account code hash and get code length. + let account = state.sdb.get_account(&address).1; + let exists = !account.is_empty(); + let code_hash = if exists { + account.code_hash + } else { + H256::zero() + }; + state.account_read( + &mut exec_step, + address, + AccountField::CodeHash, + code_hash.to_word(), + ); + let code_size = if exists { + state.code(code_hash)?.len() + } else { + 0 + }; + + // Write the EXTCODESIZE result to stack. + debug_assert_eq!(code_size, geth_steps[1].stack.last()?.as_usize()); state.stack_write( &mut exec_step, geth_steps[1].stack.nth_last_filled(0), - geth_steps[1].stack.nth_last(0)?, + code_size.into(), )?; Ok(vec![exec_step]) } } + +#[cfg(test)] +mod extcodesize_tests { + use super::*; + use crate::{ + circuit_input_builder::ExecState, + mock::BlockData, + operation::{AccountOp, CallContextOp, StackOp, RW}, + state_db::CodeDB, + }; + use eth_types::{ + bytecode, + evm_types::{OpcodeId, StackAddress}, + geth_types::{Account, GethData}, + Bytecode, U256, + }; + use mock::{TestContext, MOCK_1_ETH, MOCK_ACCOUNTS, MOCK_CODES}; + use pretty_assertions::assert_eq; + + #[test] + fn test_extcodesize_opcode() { + let account = Account { + address: MOCK_ACCOUNTS[4], + code: MOCK_CODES[4].clone(), + ..Default::default() + }; + + // Test for empty account. + test_ok(&Account::default(), false); + // Test for cold account. + test_ok(&account, false); + // Test for warm account. + test_ok(&account, true); + } + + fn test_ok(account: &Account, is_warm: bool) { + let exists = !account.is_empty(); + + let mut bytecode = Bytecode::default(); + if is_warm { + bytecode.append(&bytecode! { + PUSH20(account.address.to_word()) + EXTCODESIZE + POP + }); + } + bytecode.append(&bytecode! { + PUSH20(account.address.to_word()) + EXTCODESIZE + STOP + }); + + // Get the execution steps from the external tracer. + let block: GethData = TestContext::<3, 1>::new( + None, + |accs| { + accs[0] + .address(MOCK_ACCOUNTS[0]) + .balance(*MOCK_1_ETH) + .code(bytecode); + if exists { + accs[1].address(account.address).code(account.code.clone()); + } else { + accs[1].address(MOCK_ACCOUNTS[1]).balance(*MOCK_1_ETH); + } + accs[2].address(MOCK_ACCOUNTS[2]).balance(*MOCK_1_ETH); + }, + |mut txs, accs| { + txs[0].to(accs[0].address).from(accs[2].address); + }, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap() + .into(); + + let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + + // Check if account address is in access list as a result of bus mapping. + assert!(builder.sdb.add_account_to_access_list(account.address)); + + let tx_id = 1; + let transaction = &builder.block.txs()[tx_id - 1]; + let call_id = transaction.calls()[0].call_id; + + let indices = transaction + .steps() + .iter() + .filter(|step| step.exec_state == ExecState::Op(OpcodeId::EXTCODESIZE)) + .last() + .unwrap() + .bus_mapping_instance + .clone(); + let container = builder.block.container; + let operation = &container.stack[indices[0].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + assert_eq!( + operation.op(), + &StackOp { + call_id, + address: StackAddress::from(1023u32), + value: account.address.to_word() + } + ); + + let operation = &container.call_context[indices[1].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + assert_eq!( + operation.op(), + &CallContextOp { + call_id, + field: CallContextField::TxId, + value: tx_id.into() + } + ); + + let operation = &container.call_context[indices[2].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + assert_eq!( + operation.op(), + &CallContextOp { + call_id, + field: CallContextField::RwCounterEndOfReversion, + value: U256::zero() + } + ); + + let operation = &container.call_context[indices[3].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + assert_eq!( + operation.op(), + &CallContextOp { + call_id, + field: CallContextField::IsPersistent, + value: U256::one() + } + ); + + let operation = &container.tx_access_list_account[indices[4].as_usize()]; + assert_eq!(operation.rw(), RW::WRITE); + assert_eq!( + operation.op(), + &TxAccessListAccountOp { + tx_id, + address: account.address, + is_warm: true, + is_warm_prev: is_warm + } + ); + + let code_hash = CodeDB::hash(&account.code).to_word(); + let operation = &container.account[indices[5].as_usize()]; + assert_eq!(operation.rw(), RW::READ); + assert_eq!( + operation.op(), + &AccountOp { + address: account.address, + field: AccountField::CodeHash, + value: if exists { code_hash } else { U256::zero() }, + value_prev: if exists { code_hash } else { U256::zero() }, + } + ); + + let operation = &container.stack[indices[6].as_usize()]; + assert_eq!(operation.rw(), RW::WRITE); + assert_eq!( + operation.op(), + &StackOp { + call_id, + address: 1023u32.into(), + value: (if exists { account.code.len() } else { 0 }).into(), + } + ); + } +} diff --git a/bus-mapping/src/evm/opcodes/gasprice.rs b/bus-mapping/src/evm/opcodes/gasprice.rs index 91ae37b822..44f0c60de4 100644 --- a/bus-mapping/src/evm/opcodes/gasprice.rs +++ b/bus-mapping/src/evm/opcodes/gasprice.rs @@ -1,7 +1,9 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::operation::CallContextField; -use crate::Error; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + operation::CallContextField, + Error, +}; use eth_types::GethExecStep; /// Placeholder structure used to implement [`Opcode`] trait over it diff --git a/bus-mapping/src/evm/opcodes/logs.rs b/bus-mapping/src/evm/opcodes/logs.rs index 39131d7b5e..70b1a98041 100644 --- a/bus-mapping/src/evm/opcodes/logs.rs +++ b/bus-mapping/src/evm/opcodes/logs.rs @@ -1,10 +1,12 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecState, ExecStep}; -use crate::circuit_input_builder::{CopyDataType, CopyEvent, NumberOrHash}; -use crate::operation::{CallContextField, TxLogField}; -use crate::Error; -use eth_types::Word; -use eth_types::{GethExecStep, ToWord}; +use crate::{ + circuit_input_builder::{ + CircuitInputStateRef, CopyDataType, CopyEvent, ExecState, ExecStep, NumberOrHash, + }, + operation::{CallContextField, TxLogField}, + Error, +}; +use eth_types::{GethExecStep, ToWord, Word}; #[derive(Clone, Copy, Debug)] pub(crate) struct Log; @@ -18,7 +20,7 @@ impl Opcode for Log { let mut exec_step = gen_log_step(state, geth_step)?; if state.call()?.is_persistent { let copy_event = gen_copy_event(state, geth_step, &mut exec_step)?; - state.push_copy(copy_event); + state.push_copy(&mut exec_step, copy_event); state.tx_ctx.log_id += 1; } @@ -250,7 +252,7 @@ mod log_tests { code.push(32, Word::from(msize)); code.push(32, Word::from(mstart)); code.write_op(cur_op_code); - code.write_op(OpcodeId::STOP); + code.op_stop(); // prepare memory data let pushdata = hex::decode("1234567890abcdef1234567890abcdef").unwrap(); @@ -289,7 +291,7 @@ mod log_tests { .unwrap(); let is_persistent = builder.block.txs()[0].calls()[0].is_persistent; - let callee_address = builder.block.txs()[0].to; + let callee_address = builder.block.txs()[0].tx.to_or_contract_addr(); let step = builder.block.txs()[0] .steps() diff --git a/bus-mapping/src/evm/opcodes/memory_expansion_test.rs b/bus-mapping/src/evm/opcodes/memory_expansion_test.rs index 0be9c22ffa..48cdcbc2d2 100644 --- a/bus-mapping/src/evm/opcodes/memory_expansion_test.rs +++ b/bus-mapping/src/evm/opcodes/memory_expansion_test.rs @@ -1,16 +1,11 @@ -use eth_types::geth_types::GethData; -use eth_types::{bytecode, word, Bytecode, GethExecStep}; -use mock::test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}; -use mock::test_ctx::LoggerConfig; -use mock::TestContext; - -fn might_neg_index(index: isize, len: usize) -> usize { - if index < 0 { - (len as isize + index) as usize - } else { - index as usize - } -} +use eth_types::{bytecode, geth_types::GethData, word, Bytecode, GethExecStep}; +use mock::{ + test_ctx::{ + helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, + LoggerConfig, + }, + TestContext, +}; fn assert_expanded(_traces: &[GethExecStep], _before: isize, _after: isize) { // FIXME: memory is removed diff --git a/bus-mapping/src/evm/opcodes/mload.rs b/bus-mapping/src/evm/opcodes/mload.rs index 1535be80f8..ba6a71770a 100644 --- a/bus-mapping/src/evm/opcodes/mload.rs +++ b/bus-mapping/src/evm/opcodes/mload.rs @@ -1,8 +1,9 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::Error; -use eth_types::evm_types::MemoryAddress; -use eth_types::{GethExecStep, ToBigEndian}; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + Error, +}; +use eth_types::{evm_types::MemoryAddress, GethExecStep, ToBigEndian}; /// Placeholder structure used to implement [`Opcode`] trait over it /// corresponding to the [`OpcodeId::MLOAD`](crate::evm::OpcodeId::MLOAD) @@ -19,7 +20,6 @@ impl Opcode for Mload { ) -> Result, Error> { let geth_step = &geth_steps[0]; let mut exec_step = state.new_step(geth_step)?; - // // First stack read // let stack_value_read = geth_step.stack.last()?; @@ -34,12 +34,10 @@ impl Opcode for Mload { // 0. let mem_read_value = geth_steps[1].stack.last()?; - // // First stack write // state.stack_write(&mut exec_step, stack_position, mem_read_value)?; - // // First mem read -> 32 MemoryOp generated. // for byte in mem_read_value.to_be_bytes() { diff --git a/bus-mapping/src/evm/opcodes/mstore.rs b/bus-mapping/src/evm/opcodes/mstore.rs index 80f1fb862a..da1eacc47f 100644 --- a/bus-mapping/src/evm/opcodes/mstore.rs +++ b/bus-mapping/src/evm/opcodes/mstore.rs @@ -1,8 +1,9 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::Error; -use eth_types::evm_types::MemoryAddress; -use eth_types::{GethExecStep, ToBigEndian, ToLittleEndian}; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + Error, +}; +use eth_types::{evm_types::MemoryAddress, GethExecStep, ToBigEndian, ToLittleEndian}; /// Placeholder structure used to implement [`Opcode`] trait over it /// corresponding to the [`OpcodeId::MSTORE`](crate::evm::OpcodeId::MSTORE) diff --git a/bus-mapping/src/evm/opcodes/origin.rs b/bus-mapping/src/evm/opcodes/origin.rs index ff01759af4..551b5e6ce4 100644 --- a/bus-mapping/src/evm/opcodes/origin.rs +++ b/bus-mapping/src/evm/opcodes/origin.rs @@ -1,7 +1,9 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::operation::CallContextField; -use crate::Error; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + operation::CallContextField, + Error, +}; use eth_types::GethExecStep; #[derive(Debug, Copy, Clone)] diff --git a/bus-mapping/src/evm/opcodes/return.rs b/bus-mapping/src/evm/opcodes/return.rs deleted file mode 100644 index 8113ba8940..0000000000 --- a/bus-mapping/src/evm/opcodes/return.rs +++ /dev/null @@ -1,213 +0,0 @@ -use super::Opcode; -use crate::circuit_input_builder::{CopyDataType, CopyEvent, NumberOrHash}; -use crate::operation::MemoryOp; -use crate::{ - circuit_input_builder::CircuitInputStateRef, - evm::opcodes::ExecStep, - operation::{CallContextField, RW}, - Error, -}; -use eth_types::{Bytecode, GethExecStep, ToWord, H256}; -use ethers_core::utils::keccak256; - -#[derive(Debug, Copy, Clone)] -pub(crate) struct Return; - -// TODO: rename to indicate this handles REVERT (and maybe STOP)? -impl Opcode for Return { - fn gen_associated_ops( - state: &mut CircuitInputStateRef, - steps: &[GethExecStep], - ) -> Result, Error> { - let step = &steps[0]; - let mut exec_step = state.new_step(step)?; - - let offset = step.stack.nth_last(0)?; - let length = step.stack.nth_last(1)?; - state.stack_read(&mut exec_step, step.stack.nth_last_filled(0), offset)?; - state.stack_read(&mut exec_step, step.stack.nth_last_filled(1), length)?; - - if !length.is_zero() { - state - .call_ctx_mut()? - .memory - .extend_at_least((offset.low_u64() + length.low_u64()).try_into().unwrap()); - } - - let call = state.call()?.clone(); - state.call_context_read( - &mut exec_step, - call.call_id, - CallContextField::IsSuccess, - call.is_success.to_word(), - ); - - let offset = offset.as_usize(); - let length = length.as_usize(); - - // Case A in the spec. - if call.is_create() && call.is_success && length > 0 { - // Note: handle_return updates state.code_db. All we need to do here is push the - // copy event. - handle_create( - state, - &mut exec_step, - Source { - id: call.call_id, - offset, - length, - }, - )?; - } - - // Case B in the specs. - if call.is_root { - state.call_context_read( - &mut exec_step, - call.call_id, - CallContextField::IsPersistent, - call.is_persistent.to_word(), - ); - } - - // Case C in the specs. - if !call.is_root { - state.handle_restore_context(steps, &mut exec_step)?; - } - - // Case D in the specs. - if !call.is_root && !call.is_create() { - for (field, value) in [ - (CallContextField::ReturnDataOffset, call.return_data_offset), - (CallContextField::ReturnDataLength, call.return_data_length), - ] { - state.call_context_read(&mut exec_step, call.call_id, field, value.into()); - } - - let return_data_length = usize::try_from(call.return_data_length).unwrap(); - let copy_length = std::cmp::min(return_data_length, length); - if copy_length > 0 { - // reconstruction - let callee_memory = state.call_ctx()?.memory.clone(); - let caller_ctx = state.caller_ctx_mut()?; - let return_offset = call.return_data_offset.try_into().unwrap(); - - caller_ctx.memory.0[return_offset..return_offset + copy_length] - .copy_from_slice(&callee_memory.0[offset..offset + copy_length]); - caller_ctx.return_data.resize(length, 0); - caller_ctx.return_data[0..copy_length] - .copy_from_slice(&callee_memory.0[offset..offset + copy_length]); - - handle_copy( - state, - &mut exec_step, - Source { - id: call.call_id, - offset, - length, - }, - Destination { - id: call.caller_id, - offset: return_offset, - length: return_data_length, - }, - )?; - } - } - - state.handle_return(step)?; - Ok(vec![exec_step]) - } -} - -struct Source { - id: usize, - offset: usize, - length: usize, -} - -struct Destination { - id: usize, - offset: usize, - length: usize, -} - -fn handle_copy( - state: &mut CircuitInputStateRef, - step: &mut ExecStep, - source: Source, - destination: Destination, -) -> Result<(), Error> { - let copy_length = std::cmp::min(source.length, destination.length); - let bytes: Vec<_> = state.call_ctx()?.memory.0[source.offset..source.offset + copy_length] - .iter() - .map(|byte| (*byte, false)) - .collect(); - - let rw_counter_start = state.block_ctx.rwc; - for (i, (byte, _is_code)) in bytes.iter().enumerate() { - state.push_op( - step, - RW::READ, - MemoryOp::new(source.id, (source.offset + i).into(), *byte), - ); - state.push_op( - step, - RW::WRITE, - MemoryOp::new(destination.id, (destination.offset + i).into(), *byte), - ); - } - - state.push_copy(CopyEvent { - rw_counter_start, - src_type: CopyDataType::Memory, - src_id: NumberOrHash::Number(source.id), - src_addr: source.offset.try_into().unwrap(), - src_addr_end: (source.offset + source.length).try_into().unwrap(), - dst_type: CopyDataType::Memory, - dst_id: NumberOrHash::Number(destination.id), - dst_addr: destination.offset.try_into().unwrap(), - log_id: None, - bytes, - }); - - Ok(()) -} - -fn handle_create( - state: &mut CircuitInputStateRef, - step: &mut ExecStep, - source: Source, -) -> Result<(), Error> { - let values = state.call_ctx()?.memory.0[source.offset..source.offset + source.length].to_vec(); - let dst_id = NumberOrHash::Hash(H256(keccak256(&values))); - let bytes: Vec<_> = Bytecode::from(values) - .code - .iter() - .map(|element| (element.value, element.is_code)) - .collect(); - - let rw_counter_start = state.block_ctx.rwc; - for (i, (byte, _)) in bytes.iter().enumerate() { - state.push_op( - step, - RW::READ, - MemoryOp::new(source.id, (source.offset + i).into(), *byte), - ); - } - - state.push_copy(CopyEvent { - rw_counter_start, - src_type: CopyDataType::Memory, - src_id: NumberOrHash::Number(source.id), - src_addr: source.offset.try_into().unwrap(), - src_addr_end: (source.offset + source.length).try_into().unwrap(), - dst_type: CopyDataType::Bytecode, - dst_id, - dst_addr: 0, - log_id: None, - bytes, - }); - - Ok(()) -} diff --git a/bus-mapping/src/evm/opcodes/return_revert.rs b/bus-mapping/src/evm/opcodes/return_revert.rs new file mode 100644 index 0000000000..d81d63b021 --- /dev/null +++ b/bus-mapping/src/evm/opcodes/return_revert.rs @@ -0,0 +1,345 @@ +use super::Opcode; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, CopyDataType, CopyEvent, NumberOrHash}, + evm::opcodes::ExecStep, + operation::{AccountField, AccountOp, CallContextField, MemoryOp, RW}, + state_db::CodeDB, + Error, +}; +use eth_types::{Bytecode, GethExecStep, ToWord, H256}; + +#[derive(Debug, Copy, Clone)] +pub(crate) struct ReturnRevert; + +// TODO: rename to indicate this handles REVERT (and maybe STOP)? +impl Opcode for ReturnRevert { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + steps: &[GethExecStep], + ) -> Result, Error> { + let step = &steps[0]; + let mut exec_step = state.new_step(step)?; + + let offset = step.stack.nth_last(0)?; + let length = step.stack.nth_last(1)?; + state.stack_read(&mut exec_step, step.stack.nth_last_filled(0), offset)?; + state.stack_read(&mut exec_step, step.stack.nth_last_filled(1), length)?; + + if !length.is_zero() { + state + .call_ctx_mut()? + .memory + .extend_at_least((offset.low_u64() + length.low_u64()).try_into().unwrap()); + } + + let call = state.call()?.clone(); + state.call_context_read( + &mut exec_step, + call.call_id, + CallContextField::IsSuccess, + call.is_success.to_word(), + ); + + // Get low Uint64 of offset to generate copy steps. Since offset could + // be Uint64 overflow if length is zero. + let offset = offset.low_u64() as usize; + let length = length.as_usize(); + + // Case A in the spec. + if call.is_create() && call.is_success && length > 0 { + // Note: handle_return updates state.code_db. All we need to do here is push the + // copy event. + let code_hash = handle_create( + state, + &mut exec_step, + Source { + id: call.call_id, + offset, + length, + }, + )?; + + for (field, value) in [ + (CallContextField::CallerId, call.caller_id.to_word()), + (CallContextField::CalleeAddress, call.address.to_word()), + ( + CallContextField::RwCounterEndOfReversion, + call.rw_counter_end_of_reversion.to_word(), + ), + (CallContextField::IsPersistent, call.is_persistent.to_word()), + ] { + state.call_context_read(&mut exec_step, state.call()?.call_id, field, value); + } + + state.push_op_reversible( + &mut exec_step, + AccountOp { + address: state.call()?.address, + field: AccountField::CodeHash, + value: code_hash.to_word(), + value_prev: CodeDB::empty_code_hash().to_word(), + }, + )?; + } + + // Case B in the specs. + if call.is_root { + state.call_context_read( + &mut exec_step, + call.call_id, + CallContextField::IsPersistent, + call.is_persistent.to_word(), + ); + } + + // Case C in the specs. + if !call.is_root { + state.handle_restore_context(&mut exec_step, steps)?; + } + + // Case D in the specs. + if !call.is_root && !call.is_create() { + for (field, value) in [ + (CallContextField::ReturnDataOffset, call.return_data_offset), + (CallContextField::ReturnDataLength, call.return_data_length), + ] { + state.call_context_read(&mut exec_step, call.call_id, field, value.into()); + } + + let return_data_length = usize::try_from(call.return_data_length).unwrap(); + let copy_length = std::cmp::min(return_data_length, length); + if copy_length > 0 { + // reconstruction + let callee_memory = state.call_ctx()?.memory.clone(); + let caller_ctx = state.caller_ctx_mut()?; + let return_offset = call.return_data_offset.try_into().unwrap(); + + caller_ctx.memory.0[return_offset..return_offset + copy_length] + .copy_from_slice(&callee_memory.0[offset..offset + copy_length]); + + handle_copy( + state, + &mut exec_step, + Source { + id: call.call_id, + offset, + length, + }, + Destination { + id: call.caller_id, + offset: return_offset, + length: return_data_length, + }, + )?; + } + } + + state.handle_return(&mut exec_step, steps, false)?; + Ok(vec![exec_step]) + } +} + +struct Source { + id: usize, + offset: usize, + length: usize, +} + +struct Destination { + id: usize, + offset: usize, + length: usize, +} + +fn handle_copy( + state: &mut CircuitInputStateRef, + step: &mut ExecStep, + source: Source, + destination: Destination, +) -> Result<(), Error> { + let copy_length = std::cmp::min(source.length, destination.length); + let bytes: Vec<_> = state.call_ctx()?.memory.0[source.offset..source.offset + copy_length] + .iter() + .map(|byte| (*byte, false)) + .collect(); + + let rw_counter_start = state.block_ctx.rwc; + for (i, (byte, _is_code)) in bytes.iter().enumerate() { + state.push_op( + step, + RW::READ, + MemoryOp::new(source.id, (source.offset + i).into(), *byte), + ); + state.push_op( + step, + RW::WRITE, + MemoryOp::new(destination.id, (destination.offset + i).into(), *byte), + ); + } + + state.push_copy( + step, + CopyEvent { + rw_counter_start, + src_type: CopyDataType::Memory, + src_id: NumberOrHash::Number(source.id), + src_addr: source.offset.try_into().unwrap(), + src_addr_end: (source.offset + source.length).try_into().unwrap(), + dst_type: CopyDataType::Memory, + dst_id: NumberOrHash::Number(destination.id), + dst_addr: destination.offset.try_into().unwrap(), + log_id: None, + bytes, + }, + ); + + Ok(()) +} + +fn handle_create( + state: &mut CircuitInputStateRef, + step: &mut ExecStep, + source: Source, +) -> Result { + let values = state.call_ctx()?.memory.0[source.offset..source.offset + source.length].to_vec(); + let code_hash = CodeDB::hash(&values); + let dst_id = NumberOrHash::Hash(code_hash); + let bytes: Vec<_> = Bytecode::from(values) + .code + .iter() + .map(|element| (element.value, element.is_code)) + .collect(); + + let rw_counter_start = state.block_ctx.rwc; + for (i, (byte, _)) in bytes.iter().enumerate() { + state.push_op( + step, + RW::READ, + MemoryOp::new(source.id, (source.offset + i).into(), *byte), + ); + } + + state.push_copy( + step, + CopyEvent { + rw_counter_start, + src_type: CopyDataType::Memory, + src_id: NumberOrHash::Number(source.id), + src_addr: source.offset.try_into().unwrap(), + src_addr_end: (source.offset + source.length).try_into().unwrap(), + dst_type: CopyDataType::Bytecode, + dst_id, + dst_addr: 0, + log_id: None, + bytes, + }, + ); + + Ok(code_hash) +} + +#[cfg(test)] +mod return_tests { + use crate::mock::BlockData; + use eth_types::{bytecode, geth_types::GethData, word}; + use mock::{ + test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, + TestContext, MOCK_DEPLOYED_CONTRACT_BYTECODE, + }; + + #[test] + fn test_ok() { + let code = bytecode! { + PUSH21(*MOCK_DEPLOYED_CONTRACT_BYTECODE) + PUSH1(0) + MSTORE + + PUSH1 (0x15) + PUSH1 (0xB) + PUSH1 (0) + CREATE + + PUSH1 (0x20) + PUSH1 (0x20) + PUSH1 (0x20) + PUSH1 (0) + PUSH1 (0) + DUP6 + PUSH2 (0xFFFF) + CALL + STOP + }; + // Get the execution steps from the external tracer + let block: GethData = TestContext::<2, 1>::new( + None, + account_0_code_account_1_no_code(code), + tx_from_1_to_0, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap() + .into(); + + let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + } + + #[test] + fn test_revert() { + // // deployed contract + // PUSH1 0x20 + // PUSH1 0 + // PUSH1 0 + // CALLDATACOPY + // PUSH1 0x20 + // PUSH1 0 + // REVERT + // + // bytecode: 0x6020600060003760206000FD + // + // // constructor + // PUSH12 0x6020600060003760206000FD + // PUSH1 0 + // MSTORE + // PUSH1 0xC + // PUSH1 0x14 + // RETURN + // + // bytecode: 0x6B6020600060003760206000FD600052600C6014F3 + let code = bytecode! { + PUSH21(word!("6B6020600060003760206000FD600052600C6014F3")) + PUSH1(0) + MSTORE + + PUSH1 (0x15) + PUSH1 (0xB) + PUSH1 (0) + CREATE + + PUSH1 (0x20) + PUSH1 (0x20) + PUSH1 (0x20) + PUSH1 (0) + PUSH1 (0) + DUP6 + PUSH2 (0xFFFF) + CALL + STOP + }; + // Get the execution steps from the external tracer + let block: GethData = TestContext::<2, 1>::new( + None, + account_0_code_account_1_no_code(code), + tx_from_1_to_0, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap() + .into(); + + let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + } +} diff --git a/bus-mapping/src/evm/opcodes/returndatacopy.rs b/bus-mapping/src/evm/opcodes/returndatacopy.rs index 4ef08afd8d..a7830523d5 100644 --- a/bus-mapping/src/evm/opcodes/returndatacopy.rs +++ b/bus-mapping/src/evm/opcodes/returndatacopy.rs @@ -1,6 +1,11 @@ -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::evm::Opcode; -use crate::Error; +use crate::{ + circuit_input_builder::{ + CircuitInputStateRef, CopyDataType, CopyEvent, ExecStep, NumberOrHash, + }, + evm::Opcode, + operation::{CallContextField, MemoryOp, RW}, + Error, +}; use eth_types::GethExecStep; #[derive(Clone, Copy, Debug)] @@ -11,72 +16,171 @@ impl Opcode for Returndatacopy { state: &mut CircuitInputStateRef, geth_steps: &[GethExecStep], ) -> Result, Error> { - // TODO: complete `ExecStep` and circuit implementation - let exec_step = state.new_step(&geth_steps[0])?; + let geth_step = &geth_steps[0]; + let mut exec_steps = vec![gen_returndatacopy_step(state, geth_step)?]; // reconstruction let geth_step = &geth_steps[0]; - let dest_offset = geth_step.stack.nth_last(0)?; - let offset = geth_step.stack.nth_last(1)?; - let size = geth_step.stack.nth_last(2)?; + let dst_offset = geth_step.stack.nth_last(0)?; + let src_offset = geth_step.stack.nth_last(1)?; + let length = geth_step.stack.nth_last(2)?; // can we reduce this clone? let return_data = state.call_ctx()?.return_data.clone(); let call_ctx = state.call_ctx_mut()?; let memory = &mut call_ctx.memory; - let length = size.as_usize(); - if length != 0 { - let mem_starts = dest_offset.as_usize(); - let mem_ends = mem_starts + length; - let data_starts = offset.as_usize(); - let data_ends = data_starts + length; - let minimal_length = dest_offset.as_usize() + length; - if data_ends <= return_data.len() { - memory.extend_at_least(minimal_length); - memory[mem_starts..mem_ends].copy_from_slice(&return_data[data_starts..data_ends]); - } else { - assert_eq!(geth_steps.len(), 1); - // if overflows this opcode would fails current context, so - // there is no more steps. - } - } - Ok(vec![exec_step]) + memory.copy_from(dst_offset, src_offset, length, &return_data); + + let copy_event = gen_copy_event(state, geth_step)?; + state.push_copy(&mut exec_steps[0], copy_event); + Ok(exec_steps) + } +} + +fn gen_returndatacopy_step( + state: &mut CircuitInputStateRef, + geth_step: &GethExecStep, +) -> Result { + let mut exec_step = state.new_step(geth_step)?; + let memory_offset = geth_step.stack.nth_last(0)?; + let data_offset = geth_step.stack.nth_last(1)?; + let length = geth_step.stack.nth_last(2)?; + + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(0), + memory_offset, + )?; + state.stack_read( + &mut exec_step, + geth_step.stack.nth_last_filled(1), + data_offset, + )?; + state.stack_read(&mut exec_step, geth_step.stack.nth_last_filled(2), length)?; + + let call_id = state.call()?.call_id; + let call_ctx = state.call_ctx()?; + let return_data = call_ctx.return_data.clone(); + let last_callee_id = state.call()?.last_callee_id; + let last_callee_return_data_offset = state.call()?.last_callee_return_data_offset; + let last_callee_return_data_length = state.call()?.last_callee_return_data_length; + assert_eq!( + last_callee_return_data_length as usize, + return_data.len(), + "callee return data size should be correct" + ); + + // read last callee info + for (field, value) in [ + (CallContextField::LastCalleeId, last_callee_id.into()), + ( + CallContextField::LastCalleeReturnDataOffset, + last_callee_return_data_offset.into(), + ), + ( + CallContextField::LastCalleeReturnDataLength, + return_data.len().into(), + ), + ] { + state.call_context_read(&mut exec_step, call_id, field, value); + } + Ok(exec_step) +} + +fn gen_copy_steps( + state: &mut CircuitInputStateRef, + exec_step: &mut ExecStep, + src_addr: u64, + dst_addr: u64, + src_addr_end: u64, + bytes_left: u64, +) -> Result, Error> { + let mut copy_steps = Vec::with_capacity(bytes_left as usize); + let src_addr_base = state.call()?.last_callee_return_data_offset; + for idx in 0..bytes_left { + let addr = src_addr + idx; + let value = if addr < src_addr_end { + state.call_ctx()?.return_data[(addr - src_addr_base) as usize] + } else { + unreachable!("return data copy out of bound") + }; + // Read + state.push_op( + exec_step, + RW::READ, + MemoryOp::new(state.call()?.last_callee_id, addr.into(), value), + ); + + // Write + copy_steps.push((value, false)); + state.memory_write(exec_step, (dst_addr + idx).into(), value)?; } + Ok(copy_steps) +} + +fn gen_copy_event( + state: &mut CircuitInputStateRef, + geth_step: &GethExecStep, +) -> Result { + // Get low Uint64 of destination offset to generate copy steps. Since it + // could be Uint64 overflow if length is zero. + let dst_addr = geth_step.stack.nth_last(0)?.low_u64(); + let data_offset = geth_step.stack.nth_last(1)?.as_u64(); + let length = geth_step.stack.nth_last(2)?.as_u64(); + + let last_callee_return_data_offset = state.call()?.last_callee_return_data_offset; + let last_callee_return_data_length = state.call()?.last_callee_return_data_length; + let (src_addr, src_addr_end) = ( + last_callee_return_data_offset + data_offset, + last_callee_return_data_offset + last_callee_return_data_length, + ); + + let rw_counter_start = state.block_ctx.rwc; + let mut exec_step = state.new_step(geth_step)?; + let copy_steps = gen_copy_steps( + state, + &mut exec_step, + src_addr, + dst_addr, + src_addr_end, + length, + )?; + + let (src_type, dst_type, src_id, dst_id) = ( + CopyDataType::Memory, + CopyDataType::Memory, + NumberOrHash::Number(state.call()?.last_callee_id), + NumberOrHash::Number(state.call()?.call_id), + ); + + Ok(CopyEvent { + src_type, + src_id, + src_addr, + src_addr_end, + dst_type, + dst_id, + dst_addr, + log_id: None, + rw_counter_start, + bytes: copy_steps, + }) } #[cfg(test)] mod return_tests { use crate::mock::BlockData; - use eth_types::geth_types::GethData; - use eth_types::{bytecode, word}; - use mock::test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}; - use mock::TestContext; + use eth_types::{bytecode, geth_types::GethData}; + use mock::{ + test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, + TestContext, MOCK_DEPLOYED_CONTRACT_BYTECODE, + }; #[test] fn test_ok() { - // // deployed contract - // PUSH1 0x20 - // PUSH1 0 - // PUSH1 0 - // CALLDATACOPY - // PUSH1 0x20 - // PUSH1 0 - // RETURN - // - // bytecode: 0x6020600060003760206000F3 - // - // // constructor - // PUSH12 0x6020600060003760206000F3 - // PUSH1 0 - // MSTORE - // PUSH1 0xC - // PUSH1 0x14 - // RETURN - // - // bytecode: 0x6B6020600060003760206000F3600052600C6014F3 let code = bytecode! { - PUSH21(word!("6B6020600060003760206000F3600052600C6014F3")) + PUSH21(*MOCK_DEPLOYED_CONTRACT_BYTECODE) PUSH1(0) MSTORE @@ -116,68 +220,4 @@ mod return_tests { .handle_block(&block.eth_block, &block.geth_traces) .unwrap(); } - - #[test] - fn test_revert() { - // // deployed contract - // PUSH1 0x20 - // PUSH1 0 - // PUSH1 0 - // CALLDATACOPY - // PUSH1 0x20 - // PUSH1 0 - // RETURN - // - // bytecode: 0x6020600060003760206000F3 - // - // // constructor - // PUSH12 0x6020600060003760206000F3 - // PUSH1 0 - // MSTORE - // PUSH1 0xC - // PUSH1 0x14 - // RETURN - // - // bytecode: 0x6B6020600060003760206000F3600052600C6014F3 - let code = bytecode! { - PUSH21(word!("6B6020600060003760206000F3600052600C6014F3")) - PUSH1(0) - MSTORE - - PUSH1 (0x15) - PUSH1 (0xB) - PUSH1 (0) - CREATE - - PUSH1 (0x20) - PUSH1 (0x20) - PUSH1 (0x20) - PUSH1 (0) - PUSH1 (0) - DUP6 - PUSH2 (0xFFFF) - CALL - - PUSH1 (0x40) - PUSH1 (0) - PUSH1 (0x40) - RETURNDATACOPY - - STOP - }; - // Get the execution steps from the external tracer - let block: GethData = TestContext::<2, 1>::new( - None, - account_0_code_account_1_no_code(code), - tx_from_1_to_0, - |block, _tx| block.number(0xcafeu64), - ) - .unwrap() - .into(); - - let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); - builder - .handle_block(&block.eth_block, &block.geth_traces) - .unwrap(); - } } diff --git a/bus-mapping/src/evm/opcodes/returndatasize.rs b/bus-mapping/src/evm/opcodes/returndatasize.rs new file mode 100644 index 0000000000..ca576be396 --- /dev/null +++ b/bus-mapping/src/evm/opcodes/returndatasize.rs @@ -0,0 +1,144 @@ +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + operation::CallContextField, + Error, +}; + +use eth_types::GethExecStep; + +use super::Opcode; + +#[derive(Clone, Copy, Debug)] +pub(crate) struct Returndatasize; + +impl Opcode for Returndatasize { + fn gen_associated_ops( + state: &mut CircuitInputStateRef, + geth_steps: &[GethExecStep], + ) -> Result, Error> { + let geth_step = &geth_steps[0]; + let mut exec_step = state.new_step(geth_step)?; + let value = geth_steps[1].stack.last()?; + state.call_context_read( + &mut exec_step, + state.call()?.call_id, + CallContextField::LastCalleeReturnDataLength, + value, + ); + + state.stack_write( + &mut exec_step, + geth_step.stack.last_filled().map(|a| a - 1), + value, + )?; + + Ok(vec![exec_step]) + } +} + +#[cfg(test)] +mod returndatasize_tests { + use crate::{ + circuit_input_builder::{CircuitsParams, ExecState}, + mock::BlockData, + operation::{CallContextField, CallContextOp, StackOp, RW}, + }; + use eth_types::{ + bytecode, + evm_types::{OpcodeId, StackAddress}, + geth_types::GethData, + Word, + }; + use mock::{ + test_ctx::{helpers::*, TestContext}, + MOCK_DEPLOYED_CONTRACT_BYTECODE, + }; + use pretty_assertions::assert_eq; + + #[test] + fn test_ok() { + let return_data_size = 0x20; + let code = bytecode! { + PUSH21(*MOCK_DEPLOYED_CONTRACT_BYTECODE) + PUSH1(0) + MSTORE + + PUSH1 (0x15) + PUSH1 (0xB) + PUSH1 (0) + CREATE + + PUSH1 (0x20) + PUSH1 (0x20) + PUSH1 (0x20) + PUSH1 (0) + PUSH1 (0) + DUP6 + PUSH2 (0xFFFF) + CALL + + RETURNDATASIZE + + STOP + }; + // Get the execution steps from the external tracer + let block: GethData = TestContext::<2, 1>::new( + None, + account_0_code_account_1_no_code(code), + tx_from_1_to_0, + |block, _tx| block.number(0xcafeu64), + ) + .unwrap() + .into(); + + let mut builder = BlockData::new_from_geth_data_with_params( + block.clone(), + CircuitsParams { + max_rws: 512, + ..Default::default() + }, + ) + .new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + + let step = builder.block.txs()[0] + .steps() + .iter() + .find(|step| step.exec_state == ExecState::Op(OpcodeId::RETURNDATASIZE)) + .unwrap(); + + let call_id = builder.block.txs()[0].calls()[0].call_id; + assert_eq!( + { + let operation = + &builder.block.container.call_context[step.bus_mapping_instance[0].as_usize()]; + (operation.rw(), operation.op()) + }, + ( + RW::READ, + &CallContextOp { + call_id, + field: CallContextField::LastCalleeReturnDataLength, + value: Word::from(return_data_size), + } + ) + ); + assert_eq!( + { + let operation = + &builder.block.container.stack[step.bus_mapping_instance[1].as_usize()]; + (operation.rw(), operation.op()) + }, + ( + RW::WRITE, + &StackOp::new( + call_id, + StackAddress::from(1021), + Word::from(return_data_size) + ) + ) + ); + } +} diff --git a/bus-mapping/src/evm/opcodes/selfbalance.rs b/bus-mapping/src/evm/opcodes/selfbalance.rs index 35690cbdaf..e77294b859 100644 --- a/bus-mapping/src/evm/opcodes/selfbalance.rs +++ b/bus-mapping/src/evm/opcodes/selfbalance.rs @@ -1,7 +1,9 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::operation::{AccountField, CallContextField}; -use crate::Error; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + operation::{AccountField, CallContextField}, + Error, +}; use eth_types::{GethExecStep, ToWord}; #[derive(Debug, Copy, Clone)] @@ -31,8 +33,7 @@ impl Opcode for Selfbalance { callee_address, AccountField::Balance, self_balance, - self_balance, - )?; + ); // Stack write of self_balance state.stack_write( @@ -90,7 +91,7 @@ mod selfbalance_tests { .unwrap(); let call_id = builder.block.txs()[0].calls()[0].call_id; - let callee_address = builder.block.txs()[0].to; + let callee_address = builder.block.txs()[0].tx.to_or_contract_addr(); let self_balance = builder.sdb.get_account(&callee_address).1.balance; assert_eq!( diff --git a/bus-mapping/src/evm/opcodes/sha3.rs b/bus-mapping/src/evm/opcodes/sha3.rs index 50b5febfd7..ca2cc1a430 100644 --- a/bus-mapping/src/evm/opcodes/sha3.rs +++ b/bus-mapping/src/evm/opcodes/sha3.rs @@ -1,13 +1,13 @@ +use super::Opcode; use crate::{ circuit_input_builder::{ CircuitInputStateRef, CopyDataType, CopyEvent, ExecStep, NumberOrHash, }, Error, }; -use eth_types::{GethExecStep, Word, U256}; +use eth_types::{bytecode, Bytecode, GethExecStep, Word, U256}; use ethers_core::utils::keccak256; - -use super::Opcode; +use rand::{rngs::ThreadRng, Rng}; #[derive(Clone, Copy, Debug)] pub(crate) struct Sha3; @@ -40,7 +40,9 @@ impl Opcode for Sha3 { let memory = state .call_ctx()? .memory - .read_chunk(offset.as_usize().into(), size.as_usize().into()); + // Get low Uint64 of offset to generate copy steps. Since offset + // could be Uint64 overflow if length is zero. + .read_chunk(offset.low_u64().into(), size.as_usize().into()); // keccak-256 hash of the given data in memory. let sha3 = keccak256(&memory); @@ -62,66 +64,101 @@ impl Opcode for Sha3 { state.block.sha3_inputs.push(memory); let call_id = state.call()?.call_id; - state.push_copy(CopyEvent { - src_addr: offset.as_u64(), - src_addr_end: offset.as_u64() + size.as_u64(), - src_type: CopyDataType::Memory, - src_id: NumberOrHash::Number(call_id), - dst_addr: 0, - dst_type: CopyDataType::RlcAcc, - dst_id: NumberOrHash::Number(call_id), - log_id: None, - rw_counter_start, - bytes: steps, - }); + state.push_copy( + &mut exec_step, + CopyEvent { + src_addr: offset.low_u64(), + src_addr_end: offset + .low_u64() + .checked_add(size.as_u64()) + .unwrap_or(u64::MAX), + src_type: CopyDataType::Memory, + src_id: NumberOrHash::Number(call_id), + dst_addr: 0, + dst_type: CopyDataType::RlcAcc, + dst_id: NumberOrHash::Number(call_id), + log_id: None, + rw_counter_start, + bytes: steps, + }, + ); Ok(vec![exec_step]) } } -#[cfg(any(feature = "test", test))] -pub mod sha3_tests { - use eth_types::{bytecode, evm_types::OpcodeId, geth_types::GethData, Bytecode, Word}; - use ethers_core::utils::keccak256; - use mock::{ - test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, - TestContext, - }; - use rand::{random, Rng}; - - use crate::{ - circuit_input_builder::ExecState, - mock::BlockData, - operation::{MemoryOp, StackOp, RW}, - }; - +/// Generate Sha3 opcode +pub struct Sha3CodeGen { + /// The offset + pub offset: usize, + /// The size + pub size: usize, + data_len: usize, + rng: ThreadRng, +} +impl Sha3CodeGen { + /// Construct with memory less than size + pub fn mem_lt_size(offset: usize, size: usize) -> Self { + let mut rng = rand::thread_rng(); + let data_len = offset + + if size.gt(&0) { + rng.gen_range(0..size) + } else { + 0 + }; + Self { + offset, + size, + data_len, + rng, + } + } + /// Construct with memory equal to size + pub fn mem_eq_size(offset: usize, size: usize) -> Self { + let data_len = offset + size; + Self { + offset, + size, + data_len, + rng: rand::thread_rng(), + } + } + /// Construct with memory greater than size + pub fn mem_gt_size(offset: usize, size: usize) -> Self { + let mut rng = rand::thread_rng(); + let data_len = offset + + size + + if size.gt(&0) { + rng.gen_range(0..size) + } else { + 0 + }; + Self { + offset, + size, + data_len, + rng, + } + } + /// Construct with empty memory + pub fn mem_empty(offset: usize, size: usize) -> Self { + Self { + offset, + size, + data_len: 0, + rng: rand::thread_rng(), + } + } + fn rand_bytes(&mut self) -> Vec { + (0..self.data_len) + .map(|_| self.rng.gen()) + .collect::>() + } /// Generate bytecode for SHA3 opcode after having populated sufficient /// memory given the offset and size arguments for SHA3. - pub fn gen_sha3_code(offset: usize, size: usize, mem_kind: MemoryKind) -> (Bytecode, Vec) { - let mut rng = rand::thread_rng(); - let data_len = match mem_kind { - MemoryKind::LessThanSize => { - offset - + if size.gt(&0) { - rng.gen_range(0..size) - } else { - 0 - } - } - MemoryKind::EqualToSize => offset + size, - MemoryKind::MoreThanSize => { - offset - + size - + if size.gt(&0) { - rng.gen_range(0..size) - } else { - 0 - } - } - MemoryKind::Empty => 0, - }; - let data = rand_bytes(data_len); - let mut memory = Vec::with_capacity(data_len); + pub fn gen_sha3_code(&mut self) -> (Bytecode, Vec) { + let data = self.rand_bytes(); + let mut memory = Vec::with_capacity(self.data_len); // add opcodes to populate memory in the current context. let mut code = Bytecode::default(); @@ -135,39 +172,39 @@ pub mod sha3_tests { mem_chunk.to_vec() }; memory.extend_from_slice(&mem_value); - code.push(32, Word::from_big_endian(&mem_value)); - code.push(32, (32 * i).into()); - code.write_op(OpcodeId::MSTORE); + code.op_mstore(32 * i, Word::from_big_endian(&mem_value)); } // append SHA3 related opcodes at the tail end. let code_tail = bytecode! { - PUSH32(size) - PUSH32(offset) + PUSH32(self.size) + PUSH32(self.offset) SHA3 STOP }; code.append(&code_tail); (code, memory) } +} - /// Memory of a context with respect to the input size to SHA3. - pub enum MemoryKind { - /// Variant defining empty memory. - Empty, - /// Variant defining memory length being less than size. - LessThanSize, - /// Variant defining memory length being equal to size. - EqualToSize, - /// Variant defining memory length being more than size. - MoreThanSize, - } +#[cfg(test)] +pub(crate) mod sha3_tests { + use super::Sha3CodeGen; + use eth_types::{evm_types::OpcodeId, geth_types::GethData, Word}; + use ethers_core::utils::keccak256; + use mock::{ + test_ctx::helpers::{account_0_code_account_1_no_code, tx_from_1_to_0}, + TestContext, + }; - fn rand_bytes(size: usize) -> Vec { - (0..size).map(|_| random()).collect::>() - } + use crate::{ + circuit_input_builder::{CircuitsParams, ExecState}, + mock::BlockData, + operation::{MemoryOp, StackOp, RW}, + }; - fn test_ok(offset: usize, size: usize, mem_kind: MemoryKind) { - let (code, memory) = gen_sha3_code(offset, size, mem_kind); + fn test_ok(mut gen: Sha3CodeGen) { + let (code, memory) = gen.gen_sha3_code(); + let (size, offset) = (gen.size, gen.offset); let memory_len = memory.len(); // The memory that is hashed. @@ -188,7 +225,14 @@ pub mod sha3_tests { .unwrap() .into(); - let mut builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder(); + let mut builder = BlockData::new_from_geth_data_with_params( + block.clone(), + CircuitsParams { + max_rws: 2048, + ..Default::default() + }, + ) + .new_circuit_input_builder(); builder .handle_block(&block.eth_block, &block.geth_traces) .unwrap(); @@ -257,9 +301,9 @@ pub mod sha3_tests { #[test] fn sha3_opcode_ok() { - test_ok(0x10, 0x32, MemoryKind::Empty); - test_ok(0x34, 0x44, MemoryKind::LessThanSize); - test_ok(0x222, 0x111, MemoryKind::EqualToSize); - test_ok(0x20, 0x30, MemoryKind::MoreThanSize); + test_ok(Sha3CodeGen::mem_empty(0x10, 0x32)); + test_ok(Sha3CodeGen::mem_lt_size(0x34, 0x44)); + test_ok(Sha3CodeGen::mem_eq_size(0x222, 0x111)); + test_ok(Sha3CodeGen::mem_gt_size(0x20, 0x30)); } } diff --git a/bus-mapping/src/evm/opcodes/sload.rs b/bus-mapping/src/evm/opcodes/sload.rs index 4b4e765eff..cf06d081d9 100644 --- a/bus-mapping/src/evm/opcodes/sload.rs +++ b/bus-mapping/src/evm/opcodes/sload.rs @@ -1,8 +1,7 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::operation::CallContextField; use crate::{ - operation::{StorageOp, TxAccessListAccountStorageOp, RW}, + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + operation::{CallContextField, StorageOp, TxAccessListAccountStorageOp, RW}, Error, }; use eth_types::{GethExecStep, ToWord, Word}; @@ -85,7 +84,6 @@ impl Opcode for Sload { state.stack_write(&mut exec_step, stack_position, value)?; state.push_op_reversible( &mut exec_step, - RW::WRITE, TxAccessListAccountStorageOp { tx_id: state.tx_ctx.id(), address: contract_addr, diff --git a/bus-mapping/src/evm/opcodes/sstore.rs b/bus-mapping/src/evm/opcodes/sstore.rs index e075616e10..53feaf3549 100644 --- a/bus-mapping/src/evm/opcodes/sstore.rs +++ b/bus-mapping/src/evm/opcodes/sstore.rs @@ -1,8 +1,7 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::operation::{CallContextField, TxRefundOp}; use crate::{ - operation::{StorageOp, TxAccessListAccountStorageOp, RW}, + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + operation::{CallContextField, StorageOp, TxAccessListAccountStorageOp, TxRefundOp}, Error, }; @@ -77,7 +76,6 @@ impl Opcode for Sstore { state.push_op_reversible( &mut exec_step, - RW::WRITE, StorageOp::new( state.call()?.address, key, @@ -90,7 +88,6 @@ impl Opcode for Sstore { state.push_op_reversible( &mut exec_step, - RW::WRITE, TxAccessListAccountStorageOp { tx_id: state.tx_ctx.id(), address: state.call()?.address, @@ -102,7 +99,6 @@ impl Opcode for Sstore { state.push_op_reversible( &mut exec_step, - RW::WRITE, TxRefundOp { tx_id: state.tx_ctx.id(), value_prev: state.sdb.refund(), @@ -117,15 +113,18 @@ impl Opcode for Sstore { #[cfg(test)] mod sstore_tests { use super::*; - use crate::circuit_input_builder::ExecState; - use crate::mock::BlockData; - use crate::operation::{CallContextOp, StackOp}; - use eth_types::bytecode; - use eth_types::evm_types::{OpcodeId, StackAddress}; - use eth_types::geth_types::GethData; - use eth_types::Word; - use mock::test_ctx::helpers::tx_from_1_to_0; - use mock::{TestContext, MOCK_ACCOUNTS}; + use crate::{ + circuit_input_builder::ExecState, + mock::BlockData, + operation::{CallContextOp, StackOp, RW}, + }; + use eth_types::{ + bytecode, + evm_types::{OpcodeId, StackAddress}, + geth_types::GethData, + Word, + }; + use mock::{test_ctx::helpers::tx_from_1_to_0, TestContext, MOCK_ACCOUNTS}; use pretty_assertions::assert_eq; fn test_ok(is_warm: bool) { diff --git a/bus-mapping/src/evm/opcodes/stackonlyop.rs b/bus-mapping/src/evm/opcodes/stackonlyop.rs index 6701e4e844..21ec6bdcfe 100644 --- a/bus-mapping/src/evm/opcodes/stackonlyop.rs +++ b/bus-mapping/src/evm/opcodes/stackonlyop.rs @@ -1,6 +1,8 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::Error; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + Error, +}; use eth_types::GethExecStep; /// Placeholder structure used to implement [`Opcode`] trait over it @@ -43,8 +45,11 @@ impl Opcode for StackOnlyOpcode( opcode: OpcodeId, @@ -107,35 +116,57 @@ mod stackonlyop_tests { } #[test] - fn not_opcode_impl() { - stack_only_opcode_impl::<1, 1>( - OpcodeId::NOT, + fn sdiv_opcode_impl() { + stack_only_opcode_impl::<2, 1>( + OpcodeId::SDIV, bytecode! { - PUSH32(word!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")) - NOT + PUSH1(0x80u64) + PUSH1(0x60u64) + SDIV STOP }, + vec![ + StackOp::new(1, StackAddress(1022), Word::from(0x60)), + StackOp::new(1, StackAddress(1023), Word::from(0x80)), + ], vec![StackOp::new( 1, StackAddress(1023), - word!("0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), + Word::from(0x60) / Word::from(0x80), )], + ); + } + + #[test] + fn mod_opcode_impl() { + stack_only_opcode_impl::<2, 1>( + OpcodeId::MOD, + bytecode! { + PUSH1(0x80u64) + PUSH1(0x60u64) + MOD + STOP + }, + vec![ + StackOp::new(1, StackAddress(1022), Word::from(0x60)), + StackOp::new(1, StackAddress(1023), Word::from(0x80)), + ], vec![StackOp::new( 1, StackAddress(1023), - word!("0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0"), + Word::from(0x60) % Word::from(0x80), )], ); } #[test] - fn add_opcode_impl() { + fn smod_opcode_impl() { stack_only_opcode_impl::<2, 1>( - OpcodeId::ADD, + OpcodeId::SMOD, bytecode! { PUSH1(0x80u64) PUSH1(0x60u64) - ADD + SMOD STOP }, vec![ @@ -145,28 +176,232 @@ mod stackonlyop_tests { vec![StackOp::new( 1, StackAddress(1023), - Word::from(0x60) + Word::from(0x80), + Word::from(0x60) % Word::from(0x80), )], ); } + fn lt_opcode_impl(a: usize, b: usize, result: usize) { + stack_only_opcode_impl::<2, 1>( + OpcodeId::LT, + bytecode! { + PUSH1(b) + PUSH1(a) + LT + STOP + }, + vec![ + StackOp::new(1, StackAddress(1022), Word::from(a)), + StackOp::new(1, StackAddress(1023), Word::from(b)), + ], + vec![StackOp::new(1, StackAddress(1023), Word::from(result))], + ); + } + + #[test] + fn test_lt_opcode() { + lt_opcode_impl(0x01, 0x02, 0x01); + lt_opcode_impl(0x01, 0x01, 0x00); + lt_opcode_impl(0x02, 0x01, 0x00); + } + + fn gt_opcode_impl(a: usize, b: usize, result: usize) { + stack_only_opcode_impl::<2, 1>( + OpcodeId::GT, + bytecode! { + PUSH1(b) + PUSH1(a) + GT + STOP + }, + vec![ + StackOp::new(1, StackAddress(1022), Word::from(a)), + StackOp::new(1, StackAddress(1023), Word::from(b)), + ], + vec![StackOp::new(1, StackAddress(1023), Word::from(result))], + ); + } + #[test] + fn test_gt_opcode() { + gt_opcode_impl(0x01, 0x02, 0x00); + gt_opcode_impl(0x01, 0x01, 0x00); + gt_opcode_impl(0x02, 0x01, 0x01); + } + + fn slt_opcode_impl(a: usize, b: usize, result: usize) { + stack_only_opcode_impl::<2, 1>( + OpcodeId::SLT, + bytecode! { + PUSH1(b) + PUSH1(a) + SLT + STOP + }, + vec![ + StackOp::new(1, StackAddress(1022), Word::from(a)), + StackOp::new(1, StackAddress(1023), Word::from(b)), + ], + vec![StackOp::new(1, StackAddress(1023), Word::from(result))], + ); + } + #[test] - fn addmod_opcode_impl() { - stack_only_opcode_impl::<3, 1>( - OpcodeId::ADDMOD, + fn test_slt_opcode() { + slt_opcode_impl(0x01, 0x02, 0x01); + slt_opcode_impl(0x01, 0x01, 0x00); + slt_opcode_impl(0x02, 0x01, 0x00); + } + + fn sgt_opcode_impl(a: usize, b: usize, result: usize) { + stack_only_opcode_impl::<2, 1>( + OpcodeId::SGT, bytecode! { - PUSH3(0xbcdef) - PUSH3(0x6789a) - PUSH3(0x12345) - ADDMOD + PUSH1(b) + PUSH1(a) + SGT STOP }, vec![ - StackOp::new(1, StackAddress(1021), Word::from(0x12345)), - StackOp::new(1, StackAddress(1022), Word::from(0x6789a)), - StackOp::new(1, StackAddress(1023), Word::from(0xbcdef)), + StackOp::new(1, StackAddress(1022), Word::from(a)), + StackOp::new(1, StackAddress(1023), Word::from(b)), ], - vec![StackOp::new(1, StackAddress(1023), Word::from(0x79bdf))], + vec![StackOp::new(1, StackAddress(1023), Word::from(result))], + ); + } + #[test] + fn test_sgt_opcode() { + sgt_opcode_impl(0x01, 0x02, 0x00); + sgt_opcode_impl(0x01, 0x01, 0x00); + sgt_opcode_impl(0x02, 0x01, 0x01); + } + + fn and_opcode_impl(a: usize, b: usize, result: usize) { + stack_only_opcode_impl::<2, 1>( + OpcodeId::AND, + bytecode! { + PUSH1(b) + PUSH1(a) + AND + STOP + }, + vec![ + StackOp::new(1, StackAddress(1022), Word::from(a)), + StackOp::new(1, StackAddress(1023), Word::from(b)), + ], + vec![StackOp::new(1, StackAddress(1023), Word::from(result))], + ); + } + #[test] + fn test_and_operate() { + and_opcode_impl(0x01, 0x01, 0x01); + and_opcode_impl(0x01, 0x00, 0x00); + and_opcode_impl(0x00, 0x00, 0x00); + } + + fn or_opcode_impl(a: usize, b: usize, result: usize) { + stack_only_opcode_impl::<2, 1>( + OpcodeId::OR, + bytecode! { + PUSH1(b) + PUSH1(a) + OR + STOP + }, + vec![ + StackOp::new(1, StackAddress(1022), Word::from(a)), + StackOp::new(1, StackAddress(1023), Word::from(b)), + ], + vec![StackOp::new(1, StackAddress(1023), Word::from(result))], + ); + } + #[test] + fn test_or_operate() { + or_opcode_impl(0x01, 0x01, 0x01.bitor(0x01) as usize); + or_opcode_impl(0x00, 0x01, 0x00.bitor(0x01) as usize); + or_opcode_impl(0x00, 0x00, 0x00.bitor(0x00) as usize); + } + + fn xor_opcode_impl(a: usize, b: usize, result: usize) { + stack_only_opcode_impl::<2, 1>( + OpcodeId::XOR, + bytecode! { + PUSH1(b) + PUSH1(a) + XOR + STOP + }, + vec![ + StackOp::new(1, StackAddress(1022), Word::from(a)), + StackOp::new(1, StackAddress(1023), Word::from(b)), + ], + vec![StackOp::new(1, StackAddress(1023), Word::from(result))], + ); + } + #[test] + fn test_xor_operate() { + xor_opcode_impl(0x01, 0x01, 0x01.bitxor(0x01) as usize); + xor_opcode_impl(0x01, 0x00, 0x00.bitxor(0x01) as usize); + xor_opcode_impl(0x00, 0x00, 0x00.bitxor(0x00) as usize); + } + + #[test] + fn not_opcode_impl() { + stack_only_opcode_impl::<1, 1>( + OpcodeId::NOT, + bytecode! { + PUSH32(word!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")) + NOT + STOP + }, + vec![StackOp::new( + 1, + StackAddress(1023), + word!("0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), + )], + vec![StackOp::new( + 1, + StackAddress(1023), + word!("0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0"), + )], + ); + } + + #[test] + fn difficulty_opcode_impl() { + stack_only_opcode_impl::<0, 1>( + OpcodeId::DIFFICULTY, + bytecode! { + DIFFICULTY + STOP + }, + vec![], + vec![StackOp::new(1, StackAddress(1023), *MOCK_DIFFICULTY)], + ); + } + + #[test] + fn gas_limit_opcode_impl() { + stack_only_opcode_impl::<0, 1>( + OpcodeId::GASLIMIT, + bytecode! { + GASLIMIT + STOP + }, + vec![], + vec![StackOp::new(1, StackAddress(1023), *MOCK_GASLIMIT)], + ); + } + + #[test] + fn basefee_opcode_impl() { + stack_only_opcode_impl::<0, 1>( + OpcodeId::BASEFEE, + bytecode! { + BASEFEE + STOP + }, + vec![], + vec![StackOp::new(1, StackAddress(1023), *MOCK_BASEFEE)], ); } } diff --git a/bus-mapping/src/evm/opcodes/stop.rs b/bus-mapping/src/evm/opcodes/stop.rs index 7f595d9dbc..4ee0b3f47b 100644 --- a/bus-mapping/src/evm/opcodes/stop.rs +++ b/bus-mapping/src/evm/opcodes/stop.rs @@ -4,7 +4,7 @@ use crate::{ operation::CallContextField, Error, }; -use eth_types::{GethExecStep, ToWord}; +use eth_types::GethExecStep; /// Placeholder structure used to implement [`Opcode`] trait over it /// corresponding to the [`OpcodeId::STOP`](crate::evm::OpcodeId::STOP) @@ -32,58 +32,7 @@ impl Opcode for Stop { 1.into(), ); - if !call.is_root { - // The following part corresponds to - // Instruction.step_state_transition_to_restored_context - // in python spec, and should be reusable among all expected halting opcodes or - // exceptions. TODO: Refactor it as a helper function. - let caller = state.caller()?.clone(); - state.call_context_read( - &mut exec_step, - call.call_id, - CallContextField::CallerId, - caller.call_id.into(), - ); - - let geth_step_next = &geth_steps[1]; - let caller_ctx = state.caller_ctx()?; - let caller_gas_left = geth_step_next.gas.0 - geth_step.gas.0; - for (field, value) in [ - (CallContextField::IsRoot, (caller.is_root as u64).into()), - ( - CallContextField::IsCreate, - (caller.is_create() as u64).into(), - ), - (CallContextField::CodeHash, caller.code_hash.to_word()), - (CallContextField::ProgramCounter, geth_step_next.pc.0.into()), - ( - CallContextField::StackPointer, - geth_step_next.stack.stack_pointer().0.into(), - ), - (CallContextField::GasLeft, caller_gas_left.into()), - ( - CallContextField::MemorySize, - caller_ctx.memory.word_size().into(), - ), - ( - CallContextField::ReversibleWriteCounter, - state.caller_ctx()?.reversible_write_counter.into(), - ), - ] { - state.call_context_read(&mut exec_step, caller.call_id, field, value); - } - - for (field, value) in [ - (CallContextField::LastCalleeId, call.call_id.into()), - (CallContextField::LastCalleeReturnDataOffset, 0.into()), - (CallContextField::LastCalleeReturnDataLength, 0.into()), - ] { - state.call_context_write(&mut exec_step, caller.call_id, field, value); - } - } - - state.handle_return(geth_step)?; - + state.handle_return(&mut exec_step, geth_steps, !call.is_root)?; Ok(vec![exec_step]) } } diff --git a/bus-mapping/src/evm/opcodes/swap.rs b/bus-mapping/src/evm/opcodes/swap.rs index ba9b568c3d..7bf6b461cf 100644 --- a/bus-mapping/src/evm/opcodes/swap.rs +++ b/bus-mapping/src/evm/opcodes/swap.rs @@ -1,6 +1,8 @@ use super::Opcode; -use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep}; -use crate::Error; +use crate::{ + circuit_input_builder::{CircuitInputStateRef, ExecStep}, + Error, +}; use eth_types::GethExecStep; /// Placeholder structure used to implement [`Opcode`] trait over it @@ -35,8 +37,10 @@ impl Opcode for Swap { #[cfg(test)] mod swap_tests { - use crate::mock::BlockData; - use crate::operation::{StackOp, RW}; + use crate::{ + mock::BlockData, + operation::{StackOp, RW}, + }; use eth_types::{bytecode, evm_types::StackAddress, geth_types::GethData, Word}; use itertools::Itertools; use mock::test_ctx::{helpers::*, TestContext}; diff --git a/bus-mapping/src/exec_trace.rs b/bus-mapping/src/exec_trace.rs index 0e6d931b47..41e405c1cd 100644 --- a/bus-mapping/src/exec_trace.rs +++ b/bus-mapping/src/exec_trace.rs @@ -13,6 +13,7 @@ impl fmt::Debug for OperationRef { f.write_fmt(format_args!( "OperationRef{{ {}, {} }}", match self.0 { + Target::Start => "Start", Target::Memory => "Memory", Target::Stack => "Stack", Target::Storage => "Storage", @@ -20,7 +21,6 @@ impl fmt::Debug for OperationRef { Target::TxAccessListAccountStorage => "TxAccessListAccountStorage", Target::TxRefund => "TxRefund", Target::Account => "Account", - Target::AccountDestructed => "AccountDestructed", Target::CallContext => "CallContext", Target::TxReceipt => "TxReceipt", Target::TxLog => "TxLog", diff --git a/bus-mapping/src/lib.rs b/bus-mapping/src/lib.rs index 99f7493ff8..5a068e21f8 100644 --- a/bus-mapping/src/lib.rs +++ b/bus-mapping/src/lib.rs @@ -30,10 +30,10 @@ //! ## Bus Mapping //! The goal of this crate is to serve as: //! - A parsing lib for EVM execution traces. -//! - A way to infer some witness data that can only be constructed once we've -//! analyzed the full exec trace. -//! - An easy interface to collect all of the data to witness into the circuits -//! and witness it with few function calls. +//! - A way to infer some witness data that can only be constructed once we've analyzed the full +//! exec trace. +//! - An easy interface to collect all of the data to witness into the circuits and witness it with +//! few function calls. //! //! ## Parsing //! Provided a JSON file or a JSON as a stream of bytes, which contains an @@ -179,8 +179,8 @@ //! //! Once you have the trace built (following the code found above) you can //! basically: -//! - Get an iterator/vector over the `Stack`, `Memory` or `Storage` operations -//! ordered on the way the State Proof needs. +//! - Get an iterator/vector over the `Stack`, `Memory` or `Storage` operations ordered on the way +//! the State Proof needs. //! //! On that way, we would get something like this for the Memory ops: //! ```text,ignore @@ -213,8 +213,6 @@ //! See: #![cfg_attr(docsrs, feature(doc_cfg))] -// Temporary until we have more of the crate implemented. -#![allow(dead_code)] // We want to have UPPERCASE idents sometimes. #![allow(non_snake_case)] // Catch documentation errors caused by code changes. @@ -234,6 +232,7 @@ pub mod exec_trace; pub(crate) mod geth_errors; pub mod mock; pub mod operation; +pub mod precompile; pub mod rpc; pub mod state_db; pub use error::Error; diff --git a/bus-mapping/src/mock.rs b/bus-mapping/src/mock.rs index 5db03048f0..57ecae2475 100644 --- a/bus-mapping/src/mock.rs +++ b/bus-mapping/src/mock.rs @@ -1,7 +1,7 @@ //! Mock types and functions to generate mock data useful for tests use crate::{ - circuit_input_builder::{Block, CircuitInputBuilder}, + circuit_input_builder::{get_state_accesses, Block, CircuitInputBuilder, CircuitsParams}, state_db::{self, CodeDB, StateDB}, }; use eth_types::{geth_types::GethData, Word}; @@ -23,6 +23,8 @@ pub struct BlockData { pub eth_block: eth_types::Block, /// Execution Trace from geth pub geth_traces: Vec, + /// Circuits setup parameters + pub circuits_params: CircuitsParams, } impl BlockData { @@ -32,37 +34,34 @@ impl BlockData { CircuitInputBuilder::new( self.sdb.clone(), self.code_db.clone(), - Block::new(self.chain_id, self.history_hashes.clone(), &self.eth_block).unwrap(), + Block::new( + self.chain_id, + self.history_hashes.clone(), + Word::default(), + &self.eth_block, + self.circuits_params, + ) + .unwrap(), ) } - /// Create a new block from the given Geth data. - pub fn new_from_geth_data(geth_data: GethData) -> Self { + pub fn new_from_geth_data_with_params( + geth_data: GethData, + circuits_params: CircuitsParams, + ) -> Self { let mut sdb = StateDB::new(); let mut code_db = CodeDB::new(); - sdb.set_account( - &geth_data.eth_block.author.expect("Block.author"), - state_db::Account::zero(), - ); - for tx in geth_data.eth_block.transactions.iter() { - sdb.set_account(&tx.from, state_db::Account::zero()); - if let Some(to) = tx.to.as_ref() { - sdb.set_account(to, state_db::Account::zero()); - } + let access_set = get_state_accesses(&geth_data.eth_block, &geth_data.geth_traces) + .expect("state accesses"); + // Initialize all accesses accounts to zero + for addr in access_set.state.keys() { + sdb.set_account(addr, state_db::Account::zero()); } for account in geth_data.accounts { - let code_hash = code_db.insert(account.code.to_vec()); - sdb.set_account( - &account.address, - state_db::Account { - nonce: account.nonce, - balance: account.balance, - storage: account.storage, - code_hash, - }, - ); + code_db.insert(account.code.to_vec()); + sdb.set_account(&account.address, state_db::Account::from(account.clone())); } Self { @@ -72,6 +71,12 @@ impl BlockData { history_hashes: geth_data.history_hashes, eth_block: geth_data.eth_block, geth_traces: geth_data.geth_traces, + circuits_params, } } + + /// Create a new block from the given Geth data with default CircuitsParams. + pub fn new_from_geth_data(geth_data: GethData) -> Self { + Self::new_from_geth_data_with_params(geth_data, CircuitsParams::default()) + } } diff --git a/bus-mapping/src/operation.rs b/bus-mapping/src/operation.rs index 840fa63116..0de8e6cff3 100644 --- a/bus-mapping/src/operation.rs +++ b/bus-mapping/src/operation.rs @@ -1,17 +1,16 @@ //! Collection of structs and functions used to: //! - Define the internals of a [`MemoryOp`], [`StackOp`] and [`StorageOp`]. -//! - Define the actual operation types and a wrapper over them (the -//! [`Operation`] enum). -//! - Define structures that interact with operations such as -//! [`OperationContainer`]. +//! - Define the actual operation types and a wrapper over them (the [`Operation`] enum). +//! - Define structures that interact with operations such as [`OperationContainer`]. pub(crate) mod container; pub use container::OperationContainer; pub use eth_types::evm_types::{MemoryAddress, StackAddress}; +use gadgets::impl_expr; +use halo2_proofs::plonk::Expression; +use strum_macros::EnumIter; -use core::cmp::Ordering; -use core::fmt; -use core::fmt::Debug; +use core::{cmp::Ordering, fmt, fmt::Debug}; use eth_types::{Address, Word}; use std::mem::swap; @@ -54,6 +53,12 @@ impl From for usize { } } +impl From for u64 { + fn from(addr: RWCounter) -> u64 { + addr.0.try_into().expect("rwc should not overflow") + } +} + impl From for RWCounter { fn from(rwc: usize) -> Self { RWCounter(rwc) @@ -86,8 +91,10 @@ impl RWCounter { } /// Enum used to differenciate between EVM Stack, Memory and Storage operations. -#[derive(Debug, Clone, PartialEq, Eq, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, EnumIter, Hash)] pub enum Target { + /// Start is a padding operation. + Start = 1, /// Means the target of the operation is the Memory. Memory, /// Means the target of the operation is the Stack. @@ -102,8 +109,6 @@ pub enum Target { TxRefund, /// Means the target of the operation is the Account. Account, - /// Means the target of the operation is the AccountDestructed. - AccountDestructed, /// Means the target of the operation is the CallContext. CallContext, /// Means the target of the operation is the TxReceipt. @@ -112,6 +117,28 @@ pub enum Target { TxLog, } +impl_expr!(Target); + +impl From for usize { + fn from(value: Target) -> usize { + value as usize + } +} + +impl Target { + /// Returns true if the RwTable operation is reversible + pub fn is_reversible(self) -> bool { + matches!( + self, + Target::TxAccessListAccount + | Target::TxAccessListAccountStorage + | Target::TxRefund + | Target::Account + | Target::Storage + ) + } +} + /// Trait used for Operation Kinds. pub trait Op: Clone + Eq + Ord { @@ -529,7 +556,7 @@ impl Op for TxRefundOp { /// Represents a field parameter of the Account that can be accessed via EVM /// execution. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum AccountField { /// Account Nonce Nonce, @@ -606,55 +633,6 @@ impl Op for AccountOp { } } -/// Represents an Account destruction implied by a `SELFDESTRUCT` step of the -/// [`ExecStep`](crate::circuit_input_builder::ExecStep). -#[derive(Clone, PartialEq, Eq)] -pub struct AccountDestructedOp { - /// Transaction ID: Transaction index in the block starting at 1. - pub tx_id: usize, - /// Account Address - pub address: Address, - /// Whether the account is destructed. - pub is_destructed: bool, - /// Whether the account was previously destructed. - pub is_destructed_prev: bool, -} - -impl fmt::Debug for AccountDestructedOp { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("AccountDestructedOp { ")?; - f.write_fmt(format_args!( - "tx_id: {:?}, addr: {:?}, is_destructed_prev: {:?}, is_destructed: {:?}", - self.tx_id, self.address, self.is_destructed_prev, self.is_destructed - ))?; - f.write_str(" }") - } -} - -impl PartialOrd for AccountDestructedOp { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for AccountDestructedOp { - fn cmp(&self, other: &Self) -> Ordering { - (&self.tx_id, &self.address).cmp(&(&other.tx_id, &other.address)) - } -} - -impl Op for AccountDestructedOp { - fn into_enum(self) -> OpEnum { - OpEnum::AccountDestructed(self) - } - - fn reverse(&self) -> Self { - let mut rev = self.clone(); - swap(&mut rev.is_destructed, &mut rev.is_destructed_prev); - rev - } -} - /// Represents a field parameter of the CallContext that can be accessed via EVM /// execution. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] @@ -791,8 +769,8 @@ pub enum TxLogField { Topic, /// data of log entry Data, - /* TODO: Add `TopicLength` and `DataLength`, which will be used for the RLP encoding of the - * Tx Receipt */ + // TODO: Add `TopicLength` and `DataLength`, which will be used for the RLP encoding of the + // Tx Receipt } /// Represents TxLog read/write operation. @@ -881,6 +859,32 @@ pub enum TxReceiptField { LogLength, } +/// Represent a Start padding operation +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct StartOp {} + +impl PartialOrd for StartOp { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for StartOp { + fn cmp(&self, _other: &Self) -> Ordering { + Ordering::Equal + } +} + +impl Op for StartOp { + fn into_enum(self) -> OpEnum { + OpEnum::Start(self) + } + + fn reverse(&self) -> Self { + unreachable!("StartOp can't be reverted") + } +} + /// Represents TxReceipt read/write operation. #[derive(Clone, PartialEq, Eq)] pub struct TxReceiptOp { @@ -943,14 +947,14 @@ pub enum OpEnum { TxRefund(TxRefundOp), /// Account Account(AccountOp), - /// AccountDestructed - AccountDestructed(AccountDestructedOp), /// CallContext CallContext(CallContextOp), /// TxReceipt TxReceipt(TxReceiptOp), /// TxLog TxLog(TxLogOp), + /// Start + Start(StartOp), } /// Operation is a Wrapper over a type that implements Op with a RWCounter. diff --git a/bus-mapping/src/operation/container.rs b/bus-mapping/src/operation/container.rs index 5f30ace074..21d1918895 100644 --- a/bus-mapping/src/operation/container.rs +++ b/bus-mapping/src/operation/container.rs @@ -1,7 +1,7 @@ use super::{ - AccountDestructedOp, AccountOp, CallContextOp, MemoryOp, Op, OpEnum, Operation, RWCounter, - StackOp, StorageOp, Target, TxAccessListAccountOp, TxAccessListAccountStorageOp, TxLogOp, - TxReceiptOp, TxRefundOp, RW, + AccountOp, CallContextOp, MemoryOp, Op, OpEnum, Operation, RWCounter, StackOp, StartOp, + StorageOp, Target, TxAccessListAccountOp, TxAccessListAccountStorageOp, TxLogOp, TxReceiptOp, + TxRefundOp, RW, }; use crate::exec_trace::OperationRef; use itertools::Itertools; @@ -36,14 +36,14 @@ pub struct OperationContainer { pub tx_refund: Vec>, /// Operations of AccountOp pub account: Vec>, - /// Operations of AccountDestructedOp - pub account_destructed: Vec>, /// Operations of CallContextOp pub call_context: Vec>, /// Operations of TxReceiptOp pub tx_receipt: Vec>, /// Operations of TxLogOp pub tx_log: Vec>, + /// Operations of Start + pub start: Vec>, } impl Default for OperationContainer { @@ -64,10 +64,10 @@ impl OperationContainer { tx_access_list_account_storage: Vec::new(), tx_refund: Vec::new(), account: Vec::new(), - account_destructed: Vec::new(), call_context: Vec::new(), tx_receipt: Vec::new(), tx_log: Vec::new(), + start: Vec::new(), } } @@ -148,14 +148,6 @@ impl OperationContainer { }); OperationRef::from((Target::Account, self.account.len() - 1)) } - OpEnum::AccountDestructed(op) => { - self.account_destructed.push(if reversible { - Operation::new_reversible(rwc, rw, op) - } else { - Operation::new(rwc, rw, op) - }); - OperationRef::from((Target::AccountDestructed, self.account_destructed.len() - 1)) - } OpEnum::CallContext(op) => { self.call_context.push(Operation::new(rwc, rw, op)); OperationRef::from((Target::CallContext, self.call_context.len() - 1)) @@ -168,6 +160,10 @@ impl OperationContainer { self.tx_log.push(Operation::new(rwc, rw, op)); OperationRef::from((Target::TxLog, self.tx_log.len() - 1)) } + OpEnum::Start(op) => { + self.start.push(Operation::new(rwc, rw, op)); + OperationRef::from((Target::Start, self.start.len() - 1)) + } } } @@ -195,8 +191,10 @@ mod container_test { use super::*; use crate::operation::{RWCounter, RW}; - use eth_types::evm_types::{MemoryAddress, StackAddress}; - use eth_types::{Address, Word}; + use eth_types::{ + evm_types::{MemoryAddress, StackAddress}, + Address, Word, + }; #[test] fn operation_container_test() { diff --git a/bus-mapping/src/precompile.rs b/bus-mapping/src/precompile.rs new file mode 100644 index 0000000000..f082224e5d --- /dev/null +++ b/bus-mapping/src/precompile.rs @@ -0,0 +1,23 @@ +//! precompile helpers + +use eth_types::Address; +use revm_precompile::{Precompile, Precompiles}; + +/// Check if address is a precompiled or not. +pub fn is_precompiled(address: &Address) -> bool { + Precompiles::berlin() + .get(address.as_fixed_bytes()) + .is_some() +} + +pub(crate) fn execute_precompiled(address: &Address, input: &[u8], gas: u64) -> (Vec, u64) { + let Some(Precompile::Standard(precompile_fn)) = Precompiles::berlin() + .get(address.as_fixed_bytes()) else { + panic!("calling non-exist precompiled contract address") + }; + + match precompile_fn(input, gas) { + Ok((gas_cost, return_value)) => (return_value, gas_cost), + Err(_) => (vec![], gas), + } +} diff --git a/bus-mapping/src/state_db.rs b/bus-mapping/src/state_db.rs index ed14282131..905e41093b 100644 --- a/bus-mapping/src/state_db.rs +++ b/bus-mapping/src/state_db.rs @@ -1,17 +1,25 @@ //! Implementation of an in-memory key-value database to represent the //! Ethereum State Trie. -use eth_types::{Address, Hash, Word, H256, U256}; +use eth_types::{geth_types, Address, Hash, Word, H256, U256}; use ethers_core::utils::keccak256; use lazy_static::lazy_static; use std::collections::{HashMap, HashSet}; lazy_static! { static ref ACCOUNT_ZERO: Account = Account::zero(); - static ref VALUE_ZERO: Word = Word::zero(); - static ref CODE_HASH_ZERO: Hash = H256(keccak256(&[])); + /// Hash value for empty code hash. + static ref EMPTY_CODE_HASH: Hash = CodeDB::hash(&[]); + /// bytes of empty code hash, in little endian order. + pub static ref EMPTY_CODE_HASH_LE: [u8; 32] = { + let mut bytes = EMPTY_CODE_HASH.to_fixed_bytes(); + bytes.reverse(); + bytes + }; } +const VALUE_ZERO: Word = Word::zero(); + /// Memory storage for contract code by code hash. #[derive(Debug, Clone)] pub struct CodeDB(pub HashMap>); @@ -29,10 +37,20 @@ impl CodeDB { } /// Insert code indexed by code hash, and return the code hash. pub fn insert(&mut self, code: Vec) -> Hash { - let hash = H256(keccak256(&code)); + let hash = Self::hash(&code); self.0.insert(hash, code); hash } + + /// Compute hash of given code. + pub fn hash(code: &[u8]) -> Hash { + H256(keccak256(code)) + } + + /// Code hash of empty code. + pub fn empty_code_hash() -> Hash { + *EMPTY_CODE_HASH + } } /// Account of the Ethereum State Trie, which contains an in-memory key-value @@ -40,7 +58,7 @@ impl CodeDB { #[derive(Debug, PartialEq, Eq, Clone)] pub struct Account { /// Nonce - pub nonce: Word, + pub nonce: u64, /// Balance pub balance: Word, /// Storage key-value map @@ -49,23 +67,31 @@ pub struct Account { pub code_hash: Hash, } +impl From for Account { + fn from(account: geth_types::Account) -> Self { + Self { + nonce: account.nonce.as_u64(), + balance: account.balance, + storage: account.storage.clone(), + code_hash: CodeDB::hash(&account.code.to_vec()), + } + } +} + impl Account { /// Return an empty account, with all values set at zero. pub fn zero() -> Self { Self { - nonce: Word::zero(), + nonce: 0, balance: Word::zero(), storage: HashMap::new(), - code_hash: *CODE_HASH_ZERO, + code_hash: *EMPTY_CODE_HASH, } } /// Return if account is empty or not. pub fn is_empty(&self) -> bool { - self.nonce.is_zero() - && self.balance.is_zero() - && self.storage.is_empty() - && self.code_hash.eq(&CODE_HASH_ZERO) + self.nonce == 0 && self.balance.is_zero() && self.code_hash.eq(&EMPTY_CODE_HASH) } } @@ -92,14 +118,7 @@ pub struct StateDB { impl StateDB { /// Create an empty Self pub fn new() -> Self { - Self { - state: HashMap::new(), - access_list_account: HashSet::new(), - access_list_account_storage: HashSet::new(), - dirty_storage: HashMap::new(), - destructed_account: HashSet::new(), - refund: 0, - } + Self::default() } /// Set an [`Account`] at `addr` in the StateDB. @@ -148,7 +167,7 @@ impl StateDB { let (_, acc) = self.get_account(addr); match acc.storage.get(key) { Some(value) => (true, value), - None => (false, &(*VALUE_ZERO)), + None => (false, &VALUE_ZERO), } } @@ -178,16 +197,16 @@ impl StateDB { } /// Get nonce of account with `addr`. - pub fn get_nonce(&mut self, addr: &Address) -> u64 { + pub fn get_nonce(&self, addr: &Address) -> u64 { let (_, account) = self.get_account(addr); - account.nonce.as_u64() + account.nonce } /// Increase nonce of account with `addr` and return the previous value. pub fn increase_nonce(&mut self, addr: &Address) -> u64 { let (_, account) = self.get_account_mut(addr); - let nonce = account.nonce.as_u64(); - account.nonce = account.nonce + 1; + let nonce = account.nonce; + account.nonce += 1; nonce } @@ -284,12 +303,12 @@ mod statedb_tests { let (found, acc) = statedb.get_account_mut(&addr_a); assert!(!found); assert_eq!(acc, &Account::zero()); - acc.nonce = Word::from(100); + acc.nonce = 100; // Get existing account and check nonce let (found, acc) = statedb.get_account(&addr_a); assert!(found); - assert_eq!(acc.nonce, Word::from(100)); + assert_eq!(acc.nonce, 100); // Get non-existing storage key for existing account and set value let (found, value) = statedb.get_storage_mut(&addr_a, &Word::from(2)); @@ -311,7 +330,7 @@ mod statedb_tests { // Get existing account and check nonce let (found, acc) = statedb.get_account(&addr_b); assert!(found); - assert_eq!(acc.nonce, Word::zero()); + assert_eq!(acc.nonce, 0); // Get existing storage key and check value let (found, value) = statedb.get_storage(&addr_b, &Word::from(3)); diff --git a/circuit-benchmarks/.gitignore b/circuit-benchmarks/.gitignore deleted file mode 100644 index 96027b9e6e..0000000000 --- a/circuit-benchmarks/.gitignore +++ /dev/null @@ -1 +0,0 @@ -src/bench_params.rs diff --git a/circuit-benchmarks/Cargo.toml b/circuit-benchmarks/Cargo.toml index eaced86c4c..58ee36a853 100644 --- a/circuit-benchmarks/Cargo.toml +++ b/circuit-benchmarks/Cargo.toml @@ -7,11 +7,11 @@ license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_09_10" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } ark-std = { version = "0.3", features = ["print-trace"] } -zkevm-circuits = { path = "../zkevm-circuits" } +zkevm-circuits = { path = "../zkevm-circuits", features = ["test"]} keccak256 = { path = "../keccak256" } -bus-mapping = { path = "../bus-mapping" } +bus-mapping = { path = "../bus-mapping", features = ["test"] } rand_xorshift = "0.3" rand = "0.8" itertools = "0.10" diff --git a/circuit-benchmarks/build.rs b/circuit-benchmarks/build.rs deleted file mode 100644 index 30fc64c331..0000000000 --- a/circuit-benchmarks/build.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! Generate the benchmark file for State Circuit fetching the bench parameters -//! from ENV. - -use std::env::var; -use std::fs::*; -use std::io::Write; - -fn main() { - let degree: usize = var("DEGREE") - .unwrap_or_else(|_| "19".to_string()) - .parse() - .expect("Cannot parse DEGREE env var as usize"); - - // Add state_circuit module to `lib.rs` - let consts = format!("pub(crate) const DEGREE: usize = {};\n", degree); - - let mut state_file = - File::create("src/bench_params.rs").expect("Error generating bench_params.rs file"); - state_file - .write_all(consts.as_bytes()) - .expect("Error writing to bench_params.rs file"); -} diff --git a/circuit-benchmarks/src/bit_keccak.rs b/circuit-benchmarks/src/bit_keccak.rs deleted file mode 100644 index d3f1299b25..0000000000 --- a/circuit-benchmarks/src/bit_keccak.rs +++ /dev/null @@ -1,100 +0,0 @@ -//! State circuit benchmarks - -#[cfg(test)] -mod tests { - use ark_std::{end_timer, start_timer}; - use halo2_proofs::halo2curves::bn256::Fr; - use halo2_proofs::plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}; - use halo2_proofs::poly::commitment::ParamsProver; - use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}; - use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; - use halo2_proofs::poly::kzg::strategy::SingleStrategy; - use halo2_proofs::{ - halo2curves::bn256::{Bn256, G1Affine}, - transcript::{ - Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, - }, - }; - use rand::SeedableRng; - use rand_xorshift::XorShiftRng; - use std::env::var; - use zkevm_circuits::keccak_circuit::keccak_bit::KeccakBitCircuit; - - #[cfg_attr(not(feature = "benches"), ignore)] - #[test] - fn bench_bit_keccak_circuit_prover() { - let degree: u32 = var("DEGREE") - .expect("No DEGREE env var was provided") - .parse() - .expect("Cannot parse DEGREE env var as u32"); - - // Create the circuit. Leave last dozens of rows for blinding. - let mut circuit = KeccakBitCircuit::new(2usize.pow(degree) - 64); - - // Use the complete circuit - let inputs = vec![(0u8..135).collect::>(); circuit.capacity()]; - circuit.generate_witness(&inputs); - - // Initialize the polynomial commitment parameters - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - // Bench setup generation - let setup_message = format!("Setup generation with degree = {}", degree); - let start1 = start_timer!(|| setup_message); - let general_params = ParamsKZG::::setup(degree, &mut rng); - let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); - end_timer!(start1); - - // Initialize the proving key - let vk = keygen_vk(&general_params, &circuit).expect("keygen_vk should not fail"); - let pk = keygen_pk(&general_params, vk, &circuit).expect("keygen_pk should not fail"); - // Create a proof - let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); - - // Bench proof generation time - let proof_message = format!("Bit Keccak Proof generation with degree = {}", degree); - let start2 = start_timer!(|| proof_message); - create_proof::< - KZGCommitmentScheme, - ProverSHPLONK<'_, Bn256>, - Challenge255, - XorShiftRng, - Blake2bWrite, G1Affine, Challenge255>, - KeccakBitCircuit, - >( - &general_params, - &pk, - &[circuit], - &[&[]], - rng, - &mut transcript, - ) - .expect("proof generation should not fail"); - let proof = transcript.finalize(); - end_timer!(start2); - - // Bench verification time - let start3 = start_timer!(|| "Keccak Proof verification"); - let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(&proof[..]); - let strategy = SingleStrategy::new(&general_params); - - verify_proof::< - KZGCommitmentScheme, - VerifierSHPLONK<'_, Bn256>, - Challenge255, - Blake2bRead<&[u8], G1Affine, Challenge255>, - SingleStrategy<'_, Bn256>, - >( - &verifier_params, - pk.get_vk(), - strategy, - &[&[]], - &mut verifier_transcript, - ) - .expect("failed to verify bench circuit"); - end_timer!(start3); - } -} diff --git a/circuit-benchmarks/src/bytecode_circuit.rs b/circuit-benchmarks/src/bytecode_circuit.rs index 84555bfd24..42ca583f35 100644 --- a/circuit-benchmarks/src/bytecode_circuit.rs +++ b/circuit-benchmarks/src/bytecode_circuit.rs @@ -1,17 +1,21 @@ -//! State circuit benchmarks +//! Bytecode circuit benchmarks #[cfg(test)] mod tests { use ark_std::{end_timer, start_timer}; use bus_mapping::evm::OpcodeId; use eth_types::Field; - use halo2_proofs::plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}; - use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}; - use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; - use halo2_proofs::poly::kzg::strategy::SingleStrategy; use halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, - poly::commitment::ParamsProver, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, @@ -19,28 +23,38 @@ mod tests { use rand::SeedableRng; use rand_xorshift::XorShiftRng; use std::env::var; - use zkevm_circuits::bytecode_circuit::bytecode_unroller::{unroll, UnrolledBytecode}; - use zkevm_circuits::bytecode_circuit::dev::BytecodeCircuitTester; + use zkevm_circuits::{ + bytecode_circuit::{ + bytecode_unroller::{unroll, UnrolledBytecode}, + TestBytecodeCircuit, + }, + util::SubCircuit, + }; #[cfg_attr(not(feature = "benches"), ignore)] #[test] fn bench_bytecode_circuit_prover() { + let setup_prfx = crate::constants::SETUP_PREFIX; + let proof_gen_prfx = crate::constants::PROOFGEN_PREFIX; + let proof_ver_prfx = crate::constants::PROOFVER_PREFIX; let degree: u32 = var("DEGREE") .unwrap_or_else(|_| "15".to_string()) .parse() .expect("Cannot parse DEGREE env var as u32"); + // Unique string used by bench results module for parsing the result + const BENCHMARK_ID: &str = "Bytecode Circuit"; + // Contract code size exceeds 24576 bytes may not be deployable on Mainnet. const MAX_BYTECODE_LEN: usize = 24576; let num_rows = 1 << degree; - const NUM_BLINDING_ROWS: usize = 7 - 1; - let max_bytecode_row_num = num_rows - NUM_BLINDING_ROWS; + let max_bytecode_row_num = num_rows - TestBytecodeCircuit::::unusable_rows(); let bytecode_len = std::cmp::min(MAX_BYTECODE_LEN, max_bytecode_row_num); let bytecodes_num: usize = max_bytecode_row_num / bytecode_len; // Create the circuit - let bytecode_circuit = BytecodeCircuitTester::::new( + let bytecode_circuit = TestBytecodeCircuit::::new( fillup_codebytes(bytecodes_num, bytecode_len), 2usize.pow(degree), ); @@ -52,7 +66,7 @@ mod tests { ]); // Bench setup generation - let setup_message = format!("Setup generation with degree = {}", degree); + let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); let start1 = start_timer!(|| setup_message); let general_params = ParamsKZG::::setup(degree, &mut rng); let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); @@ -66,7 +80,10 @@ mod tests { let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); // Bench proof generation time - let proof_message = format!("Bytecode Proof generation with {} rows", degree); + let proof_message = format!( + "{} {} with degree = {}", + BENCHMARK_ID, proof_gen_prfx, degree + ); let start2 = start_timer!(|| proof_message); create_proof::< KZGCommitmentScheme, @@ -74,7 +91,7 @@ mod tests { Challenge255, XorShiftRng, Blake2bWrite, G1Affine, Challenge255>, - BytecodeCircuitTester, + TestBytecodeCircuit, >( &general_params, &pk, @@ -88,7 +105,7 @@ mod tests { end_timer!(start2); // Bench verification time - let start3 = start_timer!(|| "Bytecode Proof verification"); + let start3 = start_timer!(|| format!("{} {}", BENCHMARK_ID, proof_ver_prfx)); let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(&proof[..]); let strategy = SingleStrategy::new(&general_params); diff --git a/circuit-benchmarks/src/constants.rs b/circuit-benchmarks/src/constants.rs new file mode 100644 index 0000000000..9c717b2f1b --- /dev/null +++ b/circuit-benchmarks/src/constants.rs @@ -0,0 +1,5 @@ +// Prefixes to be used in benchmarks' log messages for +// consistent logging and log parsing +pub const SETUP_PREFIX: &str = "[Setup generation]"; +pub const PROOFGEN_PREFIX: &str = "[Proof generation]"; +pub const PROOFVER_PREFIX: &str = "[Proof verification]"; diff --git a/circuit-benchmarks/src/copy_circuit.rs b/circuit-benchmarks/src/copy_circuit.rs new file mode 100644 index 0000000000..e08e4aa8fd --- /dev/null +++ b/circuit-benchmarks/src/copy_circuit.rs @@ -0,0 +1,161 @@ +//! Copy circuit benchmarks + +#[cfg(test)] +mod tests { + use ark_std::{end_timer, start_timer}; + use bus_mapping::{circuit_input_builder::CircuitsParams, mock::BlockData}; + use eth_types::{bytecode, geth_types::GethData, Word}; + use halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr, G1Affine}, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, + transcript::{ + Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, + }, + }; + use mock::test_ctx::{helpers::*, TestContext}; + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + use std::env::var; + use zkevm_circuits::{ + copy_circuit::TestCopyCircuit, + evm_circuit::witness::{block_convert, Block}, + util::SubCircuit, + }; + + #[cfg_attr(not(feature = "benches"), ignore)] + #[test] + fn bench_copy_circuit_prover() { + let setup_prfx = crate::constants::SETUP_PREFIX; + let proof_gen_prfx = crate::constants::PROOFGEN_PREFIX; + let proof_ver_prfx = crate::constants::PROOFVER_PREFIX; + let degree: u32 = var("DEGREE") + .unwrap_or_else(|_| "14".to_string()) + .parse() + .expect("Cannot parse DEGREE env var as u32"); + + // Unique string used by bench results module for parsing the result + const BENCHMARK_ID: &str = "Copy Circuit"; + + // Initialize the polynomial commitment parameters + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + + // Create the circuit + let block = generate_full_events_block(degree); + let circuit = TestCopyCircuit::::new_from_block(&block); + + // Bench setup generation + let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); + let start1 = start_timer!(|| setup_message); + let general_params = ParamsKZG::::setup(degree, &mut rng); + let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); + end_timer!(start1); + + // Initialize the proving key + let vk = keygen_vk(&general_params, &circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(&general_params, vk, &circuit).expect("keygen_pk should not fail"); + // Create a proof + let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); + + // Bench proof generation time + let proof_message = format!( + "{} {} with degree = {}", + BENCHMARK_ID, proof_gen_prfx, degree + ); + let start2 = start_timer!(|| proof_message); + create_proof::< + KZGCommitmentScheme, + ProverSHPLONK<'_, Bn256>, + Challenge255, + XorShiftRng, + Blake2bWrite, G1Affine, Challenge255>, + TestCopyCircuit, + >(&general_params, &pk, &[circuit], &[], rng, &mut transcript) + .expect("proof generation should not fail"); + let proof = transcript.finalize(); + end_timer!(start2); + + // Bench verification time + let start3 = start_timer!(|| format!("{} {}", BENCHMARK_ID, proof_ver_prfx)); + let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(&proof[..]); + let strategy = SingleStrategy::new(&general_params); + + verify_proof::< + KZGCommitmentScheme, + VerifierSHPLONK<'_, Bn256>, + Challenge255, + Blake2bRead<&[u8], G1Affine, Challenge255>, + SingleStrategy<'_, Bn256>, + >( + &verifier_params, + pk.get_vk(), + strategy, + &[], + &mut verifier_transcript, + ) + .expect("failed to verify bench circuit"); + end_timer!(start3); + } + + /// generate enough copy events to fillup copy circuit + fn generate_full_events_block(degree: u32) -> Block { + // A empiric value 55 here to let the code generate enough copy event without + // exceed the max_rws limit. + let copy_event_num = (1 << degree) / 55; + let calldata = vec![0, 1, 2, 3]; + let code = bytecode! { + PUSH32(Word::from(copy_event_num)) // config loop counter + JUMPDEST // PC offset 0x21 + PUSH32(Word::from(0x04)) + PUSH32(Word::from(0x00)) + PUSH32(Word::from(0x00)) + CALLDATACOPY // do calldatacopy to generate copy event + PUSH32(Word::from(0x01)) + SWAP1 + SUB + DUP1 + PUSH32(Word::from(0x21)) + JUMPI // goto JUMPDEST(0x21) if (--copy_event_num > 0) + STOP + }; + + let test_ctx = TestContext::<2, 1>::new( + None, + account_0_code_account_1_no_code(code), + |mut txs, accs| { + txs[0] + .from(accs[1].address) + .to(accs[0].address) + .input(calldata.into()) + .gas((1e16 as u64).into()); + }, + |block, _txs| block.number(0xcafeu64), + ) + .unwrap(); + let block: GethData = test_ctx.into(); + let mut builder = BlockData::new_from_geth_data_with_params( + block.clone(), + CircuitsParams { + max_rws: 1 << (degree - 1), + ..Default::default() + }, + ) + .new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + let block = block_convert(&builder.block, &builder.code_db).unwrap(); + assert_eq!(block.copy_events.len(), copy_event_num); + block + } +} diff --git a/circuit-benchmarks/src/evm_circuit.rs b/circuit-benchmarks/src/evm_circuit.rs index 081f893d4c..aaf887261c 100644 --- a/circuit-benchmarks/src/evm_circuit.rs +++ b/circuit-benchmarks/src/evm_circuit.rs @@ -1,94 +1,69 @@ //! Evm circuit benchmarks -use eth_types::Field; -use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - plonk::{Circuit, ConstraintSystem, Error, Expression}, -}; -use zkevm_circuits::evm_circuit::{witness::Block, EvmCircuit}; -use zkevm_circuits::table::{BlockTable, BytecodeTable, RwTable, TxTable}; - -#[derive(Debug, Default)] -pub struct TestCircuit { - block: Block, -} - -impl Circuit for TestCircuit { - type Config = EvmCircuit; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let tx_table = TxTable::construct(meta); - let rw_table = RwTable::construct(meta); - let bytecode_table = BytecodeTable::construct(meta); - let block_table = BlockTable::construct(meta); - let copy_table = [(); 11].map(|_| meta.advice_column()); - let keccak_table = [(); 4].map(|_| meta.advice_column()); - // Use constant expression to mock constant instance column for a more - // reasonable benchmark. - let power_of_randomness = [(); 31].map(|_| Expression::Constant(F::one())); - - EvmCircuit::configure( - meta, - power_of_randomness, - &tx_table, - &rw_table, - &bytecode_table, - &block_table, - ©_table, - &keccak_table, - ) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - config.assign_block(&mut layouter, &self.block)?; - Ok(()) - } -} - #[cfg(test)] mod evm_circ_benches { - use super::*; use ark_std::{end_timer, start_timer}; - use halo2_proofs::plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}; - use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}; - use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; - use halo2_proofs::poly::kzg::strategy::SingleStrategy; + use bus_mapping::{circuit_input_builder::CircuitsParams, mock::BlockData}; + use eth_types::geth_types::GethData; use halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, - poly::commitment::ParamsProver, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, }; + use mock::TestContext; use rand::SeedableRng; use rand_xorshift::XorShiftRng; use std::env::var; + use zkevm_circuits::evm_circuit::{witness::block_convert, TestEvmCircuit}; #[cfg_attr(not(feature = "benches"), ignore)] #[test] fn bench_evm_circuit_prover() { + let setup_prfx = crate::constants::SETUP_PREFIX; + let proof_gen_prfx = crate::constants::PROOFGEN_PREFIX; + let proof_ver_prfx = crate::constants::PROOFVER_PREFIX; + // Unique string used by bench results module for parsing the result + const BENCHMARK_ID: &str = "EVM Circuit"; + let degree: u32 = var("DEGREE") .expect("No DEGREE env var was provided") .parse() .expect("Cannot parse DEGREE env var as u32"); - let circuit = TestCircuit::::default(); + let empty_data: GethData = TestContext::<0, 0>::new(None, |_| {}, |_, _| {}, |b, _| b) + .unwrap() + .into(); + + let mut builder = BlockData::new_from_geth_data_with_params( + empty_data.clone(), + CircuitsParams::default(), + ) + .new_circuit_input_builder(); + + builder + .handle_block(&empty_data.eth_block, &empty_data.geth_traces) + .unwrap(); + + let block = block_convert(&builder.block, &builder.code_db).unwrap(); + + let circuit = TestEvmCircuit::::new(block); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, ]); // Bench setup generation - let setup_message = format!("Setup generation with degree = {}", degree); + let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); let start1 = start_timer!(|| setup_message); let general_params = ParamsKZG::::setup(degree, &mut rng); let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); @@ -101,7 +76,10 @@ mod evm_circ_benches { let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); // Bench proof generation time - let proof_message = format!("EVM circuit Proof generation with degree = {}", degree); + let proof_message = format!( + "{} {} with degree = {}", + BENCHMARK_ID, proof_gen_prfx, degree + ); let start2 = start_timer!(|| proof_message); create_proof::< KZGCommitmentScheme, @@ -109,7 +87,7 @@ mod evm_circ_benches { Challenge255, XorShiftRng, Blake2bWrite, G1Affine, Challenge255>, - TestCircuit, + TestEvmCircuit, >( &general_params, &pk, @@ -123,7 +101,7 @@ mod evm_circ_benches { end_timer!(start2); // Bench verification time - let start3 = start_timer!(|| "EVM circuit Proof verification"); + let start3 = start_timer!(|| format!("{} {}", BENCHMARK_ID, proof_ver_prfx)); let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(&proof[..]); let strategy = SingleStrategy::new(&general_params); diff --git a/circuit-benchmarks/src/exp_circuit.rs b/circuit-benchmarks/src/exp_circuit.rs new file mode 100644 index 0000000000..35cb68f8a6 --- /dev/null +++ b/circuit-benchmarks/src/exp_circuit.rs @@ -0,0 +1,153 @@ +//! Exp circuit benchmarks + +#[cfg(test)] +mod tests { + use ark_std::{end_timer, start_timer}; + use bus_mapping::{circuit_input_builder::CircuitsParams, mock::BlockData}; + use env_logger::Env; + use eth_types::{bytecode, geth_types::GethData, Word}; + use halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr, G1Affine}, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, + transcript::{ + Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, + }, + }; + use mock::test_ctx::{helpers::*, TestContext}; + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + use std::env::var; + use zkevm_circuits::{ + evm_circuit::witness::{block_convert, Block}, + exp_circuit::TestExpCircuit, + }; + + #[cfg_attr(not(feature = "benches"), ignore)] + #[test] + fn bench_exp_circuit_prover() { + env_logger::Builder::from_env(Env::default().default_filter_or("debug")).init(); + let setup_prfx = crate::constants::SETUP_PREFIX; + let proof_gen_prfx = crate::constants::PROOFGEN_PREFIX; + let proof_ver_prfx = crate::constants::PROOFVER_PREFIX; + // Unique string used by bench results module for parsing the result + const BENCHMARK_ID: &str = "Exp Circuit"; + + // Initialize the circuit + + let degree: u32 = var("DEGREE") + .unwrap_or_else(|_| "19".to_string()) + .parse() + .expect("Cannot parse DEGREE env var as u32"); + + let base = Word::from(132); + let exponent = Word::from(27); + let block = generate_full_events_block(degree, base, exponent); + let circuit = TestExpCircuit::::new( + block.exp_events.clone(), + block.circuits_params.max_exp_steps, + ); + + // Initialize the polynomial commitment parameters + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + + // Bench setup generation + let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); + let start1 = start_timer!(|| setup_message); + let general_params = ParamsKZG::::setup(degree, &mut rng); + let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); + end_timer!(start1); + + // Initialize the proving key + let vk = keygen_vk(&general_params, &circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(&general_params, vk, &circuit).expect("keygen_pk should not fail"); + // Create a proof + let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); + + // Bench proof generation time + let proof_message = format!( + "{} {} with degree = {}", + BENCHMARK_ID, proof_gen_prfx, degree + ); + let start2 = start_timer!(|| proof_message); + create_proof::< + KZGCommitmentScheme, + ProverSHPLONK<'_, Bn256>, + Challenge255, + XorShiftRng, + Blake2bWrite, G1Affine, Challenge255>, + TestExpCircuit, + >( + &general_params, + &pk, + &[circuit], + &[&[]], + rng, + &mut transcript, + ) + .expect("proof generation should not fail"); + let proof = transcript.finalize(); + end_timer!(start2); + + // Bench verification time + let start3 = start_timer!(|| format!("{} {}", BENCHMARK_ID, proof_ver_prfx)); + let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(&proof[..]); + let strategy = SingleStrategy::new(&general_params); + + verify_proof::< + KZGCommitmentScheme, + VerifierSHPLONK<'_, Bn256>, + Challenge255, + Blake2bRead<&[u8], G1Affine, Challenge255>, + SingleStrategy<'_, Bn256>, + >( + &verifier_params, + pk.get_vk(), + strategy, + &[&[]], + &mut verifier_transcript, + ) + .expect("failed to verify bench circuit"); + end_timer!(start3); + } + + fn generate_full_events_block(degree: u32, base: Word, exponent: Word) -> Block { + let code = bytecode! { + PUSH32(exponent) + PUSH32(base) + EXP + STOP + }; + + let test_ctx = TestContext::<2, 1>::new( + None, + account_0_code_account_1_no_code(code), + tx_from_1_to_0, + |block, _txs| block.number(0xcafeu64), + ) + .unwrap(); + let block: GethData = test_ctx.into(); + let mut builder = BlockData::new_from_geth_data_with_params( + block.clone(), + CircuitsParams { + max_rws: 1 << (degree - 1), + ..Default::default() + }, + ) + .new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + block_convert(&builder.block, &builder.code_db).unwrap() + } +} diff --git a/circuit-benchmarks/src/lib.rs b/circuit-benchmarks/src/lib.rs index 7cd1a73d89..877343cd9e 100644 --- a/circuit-benchmarks/src/lib.rs +++ b/circuit-benchmarks/src/lib.rs @@ -6,28 +6,32 @@ pub mod state_circuit; #[cfg(test)] #[cfg(feature = "benches")] -pub mod bench_params; +pub mod tx_circuit; #[cfg(test)] #[cfg(feature = "benches")] -pub mod tx_circuit; +pub mod super_circuit; #[cfg(test)] #[cfg(feature = "benches")] -pub mod super_circuit; +pub mod packed_multi_keccak; #[cfg(test)] #[cfg(feature = "benches")] -pub mod bit_keccak; +pub mod bytecode_circuit; #[cfg(test)] #[cfg(feature = "benches")] -pub mod packed_keccak; +pub mod pi_circuit; #[cfg(test)] #[cfg(feature = "benches")] -pub mod packed_multi_keccak; +pub mod copy_circuit; #[cfg(test)] #[cfg(feature = "benches")] -pub mod bytecode_circuit; +pub mod exp_circuit; + +#[cfg(test)] +#[cfg(feature = "benches")] +pub mod constants; diff --git a/circuit-benchmarks/src/packed_multi_keccak.rs b/circuit-benchmarks/src/packed_multi_keccak.rs index 04653b2c0d..2810fbd984 100644 --- a/circuit-benchmarks/src/packed_multi_keccak.rs +++ b/circuit-benchmarks/src/packed_multi_keccak.rs @@ -1,15 +1,19 @@ -//! State circuit benchmarks +//! Packed multi keccak circuit benchmarks #[cfg(test)] mod tests { use ark_std::{end_timer, start_timer}; - use halo2_proofs::plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}; - use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}; - use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; - use halo2_proofs::poly::kzg::strategy::SingleStrategy; use halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, - poly::commitment::ParamsProver, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, @@ -17,22 +21,30 @@ mod tests { use rand::SeedableRng; use rand_xorshift::XorShiftRng; use std::env::var; - use zkevm_circuits::keccak_circuit::keccak_packed_multi::KeccakPackedCircuit; + use zkevm_circuits::{keccak_circuit::TestKeccakCircuit, util::SubCircuit}; #[cfg_attr(not(feature = "benches"), ignore)] #[test] fn bench_packed_multi_keccak_circuit_prover() { + let setup_prfx = crate::constants::SETUP_PREFIX; + let proof_gen_prfx = crate::constants::PROOFGEN_PREFIX; + let proof_ver_prfx = crate::constants::PROOFVER_PREFIX; + // Unique string used by bench results module for parsing the result + const BENCHMARK_ID: &str = "Packed Multi-Keccak Circuit"; + let degree: u32 = var("DEGREE") .expect("No DEGREE env var was provided") .parse() .expect("Cannot parse DEGREE env var as u32"); - // Create the circuit. Leave last dozens of rows for blinding. - let mut circuit = KeccakPackedCircuit::new(2usize.pow(degree) - 64); - // Use the complete circuit - let inputs = vec![(0u8..135).collect::>(); circuit.capacity()]; - circuit.generate_witness(&inputs); + let inputs = vec![(0u8..135).collect::>(); 3]; + + // Create the circuit. Leave last dozens of rows for blinding. + let circuit = TestKeccakCircuit::new( + 2usize.pow(degree) - TestKeccakCircuit::::unusable_rows(), + inputs, + ); // Initialize the polynomial commitment parameters let mut rng = XorShiftRng::from_seed([ @@ -41,7 +53,7 @@ mod tests { ]); // Bench setup generation - let setup_message = format!("Setup generation with degree = {}", degree); + let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); let start1 = start_timer!(|| setup_message); let general_params = ParamsKZG::::setup(degree, &mut rng); let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); @@ -55,8 +67,8 @@ mod tests { // Bench proof generation time let proof_message = format!( - "Packed Multi-Keccak Proof generation with degree = {}", - degree + "{} {} with degree = {}", + BENCHMARK_ID, proof_gen_prfx, degree ); let start2 = start_timer!(|| proof_message); create_proof::< @@ -65,7 +77,7 @@ mod tests { Challenge255, XorShiftRng, Blake2bWrite, G1Affine, Challenge255>, - KeccakPackedCircuit, + TestKeccakCircuit, >( &general_params, &pk, @@ -79,7 +91,7 @@ mod tests { end_timer!(start2); // Bench verification time - let start3 = start_timer!(|| "Packed Multi-Keccak Proof verification"); + let start3 = start_timer!(|| format!("{} {}", BENCHMARK_ID, proof_ver_prfx)); let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(&proof[..]); let strategy = SingleStrategy::new(&general_params); diff --git a/circuit-benchmarks/src/packed_keccak.rs b/circuit-benchmarks/src/pi_circuit.rs similarity index 52% rename from circuit-benchmarks/src/packed_keccak.rs rename to circuit-benchmarks/src/pi_circuit.rs index 5e252ebb36..eb1295e129 100644 --- a/circuit-benchmarks/src/packed_keccak.rs +++ b/circuit-benchmarks/src/pi_circuit.rs @@ -1,47 +1,67 @@ -//! State circuit benchmarks - +//! Public input circuit benchmarks #[cfg(test)] mod tests { use ark_std::{end_timer, start_timer}; - use halo2_proofs::plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}; - use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}; - use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; - use halo2_proofs::poly::kzg::strategy::SingleStrategy; + use eth_types::Word; use halo2_proofs::{ + arithmetic::Field, halo2curves::bn256::{Bn256, Fr, G1Affine}, - poly::commitment::ParamsProver, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, }; use rand::SeedableRng; + use rand_chacha::ChaCha20Rng; use rand_xorshift::XorShiftRng; use std::env::var; - use zkevm_circuits::keccak_circuit::keccak_packed::KeccakPackedCircuit; + use zkevm_circuits::{ + pi_circuit::{PiCircuit, PublicData}, + util::SubCircuit, + }; #[cfg_attr(not(feature = "benches"), ignore)] #[test] - fn bench_packed_keccak_circuit_prover() { + fn bench_pi_circuit_prover() { + let setup_prfx = crate::constants::SETUP_PREFIX; + let proof_gen_prfx = crate::constants::PROOFGEN_PREFIX; + let proof_ver_prfx = crate::constants::PROOFVER_PREFIX; + // Unique string used by bench results module for parsing the result + const BENCHMARK_ID: &str = "Pi Circuit"; + + const MAX_TXS: usize = 10; + const MAX_CALLDATA: usize = 128; + let degree: u32 = var("DEGREE") - .expect("No DEGREE env var was provided") + .unwrap_or_else(|_| "19".to_string()) .parse() .expect("Cannot parse DEGREE env var as u32"); - // Create the circuit. Leave last dozens of rows for blinding. - let mut circuit = KeccakPackedCircuit::new(2usize.pow(degree) - 64); + let mut rng = ChaCha20Rng::seed_from_u64(2); + let randomness = Fr::random(&mut rng); + let rand_rpi = Fr::random(&mut rng); + let public_data = generate_publicdata(MAX_TXS); + let circuit = + PiCircuit::::new(MAX_TXS, MAX_CALLDATA, randomness, rand_rpi, public_data); + let public_inputs = circuit.instance(); + let instance: Vec<&[Fr]> = public_inputs.iter().map(|input| &input[..]).collect(); + let instances = &[&instance[..]]; - // Use the complete circuit - let inputs = vec![(0u8..135).collect::>(); circuit.capacity()]; - circuit.generate_witness(&inputs); - - // Initialize the polynomial commitment parameters let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, ]); // Bench setup generation - let setup_message = format!("Setup generation with degree = {}", degree); + let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); let start1 = start_timer!(|| setup_message); let general_params = ParamsKZG::::setup(degree, &mut rng); let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); @@ -54,7 +74,10 @@ mod tests { let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); // Bench proof generation time - let proof_message = format!("Packed Keccak Proof generation with degree = {}", degree); + let proof_message = format!( + "{} {} with degree = {}", + BENCHMARK_ID, proof_gen_prfx, degree + ); let start2 = start_timer!(|| proof_message); create_proof::< KZGCommitmentScheme, @@ -62,12 +85,12 @@ mod tests { Challenge255, XorShiftRng, Blake2bWrite, G1Affine, Challenge255>, - KeccakPackedCircuit, + PiCircuit, >( &general_params, &pk, &[circuit], - &[&[]], + instances, rng, &mut transcript, ) @@ -76,7 +99,7 @@ mod tests { end_timer!(start2); // Bench verification time - let start3 = start_timer!(|| "Packed Keccak Proof verification"); + let start3 = start_timer!(|| format!("{} {}", BENCHMARK_ID, proof_ver_prfx)); let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(&proof[..]); let strategy = SingleStrategy::new(&general_params); @@ -90,10 +113,23 @@ mod tests { &verifier_params, pk.get_vk(), strategy, - &[&[]], + instances, &mut verifier_transcript, ) .expect("failed to verify bench circuit"); end_timer!(start3); } + + fn generate_publicdata(max_txs: usize) -> PublicData { + let mut public_data = PublicData::default(); + let chain_id = 1337u64; + public_data.chain_id = Word::from(chain_id); + + let n_tx = max_txs; + for _ in 0..n_tx { + let eth_tx = eth_types::Transaction::from(mock::CORRECT_MOCK_TXS[0].clone()); + public_data.transactions.push(eth_tx); + } + public_data + } } diff --git a/circuit-benchmarks/src/state_circuit.rs b/circuit-benchmarks/src/state_circuit.rs index b6a62fad7c..03eb41cbd2 100644 --- a/circuit-benchmarks/src/state_circuit.rs +++ b/circuit-benchmarks/src/state_circuit.rs @@ -3,13 +3,17 @@ #[cfg(test)] mod tests { use ark_std::{end_timer, start_timer}; - use halo2_proofs::plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}; - use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}; - use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; - use halo2_proofs::poly::kzg::strategy::SingleStrategy; use halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, - poly::commitment::ParamsProver, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, @@ -17,18 +21,25 @@ mod tests { use rand::SeedableRng; use rand_xorshift::XorShiftRng; use std::env::var; - use zkevm_circuits::evm_circuit::witness::RwMap; - use zkevm_circuits::state_circuit::StateCircuit; + use zkevm_circuits::{ + evm_circuit::witness::RwMap, state_circuit::StateCircuit, util::SubCircuit, + }; #[cfg_attr(not(feature = "benches"), ignore)] #[test] fn bench_state_circuit_prover() { + let setup_prfx = crate::constants::SETUP_PREFIX; + let proof_gen_prfx = crate::constants::PROOFGEN_PREFIX; + let proof_ver_prfx = crate::constants::PROOFVER_PREFIX; + // Unique string used by bench results module for parsing the result + const BENCHMARK_ID: &str = "State Circuit"; + let degree: u32 = var("DEGREE") .expect("No DEGREE env var was provided") .parse() .expect("Cannot parse DEGREE env var as u32"); - let empty_circuit = StateCircuit::::new(Fr::default(), RwMap::default(), 1 << 16); + let empty_circuit = StateCircuit::::new(RwMap::default(), 1 << 16); // Initialize the polynomial commitment parameters let mut rng = XorShiftRng::from_seed([ @@ -37,7 +48,7 @@ mod tests { ]); // Bench setup generation - let setup_message = format!("Setup generation with degree = {}", degree); + let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); let start1 = start_timer!(|| setup_message); let general_params = ParamsKZG::::setup(degree, &mut rng); let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); @@ -53,7 +64,10 @@ mod tests { let instances: Vec<&[Fr]> = instance.iter().map(|v| v.as_slice()).collect(); // Bench proof generation time - let proof_message = format!("State Circuit Proof generation with degree = {}", degree); + let proof_message = format!( + "{} {} with degree = {}", + BENCHMARK_ID, proof_gen_prfx, degree + ); let start2 = start_timer!(|| proof_message); create_proof::< KZGCommitmentScheme, @@ -75,7 +89,7 @@ mod tests { end_timer!(start2); // Bench verification time - let start3 = start_timer!(|| "State Circuit Proof verification"); + let start3 = start_timer!(|| format!("{} {}", BENCHMARK_ID, proof_ver_prfx)); let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(&proof[..]); let strategy = SingleStrategy::new(&general_params); diff --git a/circuit-benchmarks/src/super_circuit.rs b/circuit-benchmarks/src/super_circuit.rs index c285f1e2cf..a37ffa82d8 100644 --- a/circuit-benchmarks/src/super_circuit.rs +++ b/circuit-benchmarks/src/super_circuit.rs @@ -3,17 +3,20 @@ #[cfg(test)] mod tests { use ark_std::{end_timer, start_timer}; - use eth_types::geth_types::GethData; - use eth_types::{address, bytecode, Word}; - use ethers_signers::LocalWallet; - use ethers_signers::Signer; - use halo2_proofs::plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}; - use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}; - use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; - use halo2_proofs::poly::kzg::strategy::SingleStrategy; + use bus_mapping::circuit_input_builder::CircuitsParams; + use eth_types::{address, bytecode, geth_types::GethData, Word}; + use ethers_signers::{LocalWallet, Signer}; use halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, - poly::commitment::ParamsProver, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, @@ -21,13 +24,18 @@ mod tests { use mock::{TestContext, MOCK_CHAIN_ID}; use rand::SeedableRng; use rand_chacha::ChaChaRng; - use std::collections::HashMap; - use std::env::var; + use std::{collections::HashMap, env::var}; use zkevm_circuits::super_circuit::SuperCircuit; #[cfg_attr(not(feature = "benches"), ignore)] #[test] fn bench_super_circuit_prover() { + let setup_prfx = crate::constants::SETUP_PREFIX; + let proof_gen_prfx = crate::constants::PROOFGEN_PREFIX; + let proof_ver_prfx = crate::constants::PROOFVER_PREFIX; + // Unique string used by bench results module for parsing the result + const BENCHMARK_ID: &str = "Super Circuit"; + let degree: u32 = var("DEGREE") .expect("No DEGREE env var was provided") .parse() @@ -71,12 +79,22 @@ mod tests { block.sign(&wallets); - let (_, circuit, instance) = - SuperCircuit::<_, 1, 32>::build(block, &mut ChaChaRng::seed_from_u64(2)).unwrap(); + let circuits_params = CircuitsParams { + max_txs: 1, + max_calldata: 32, + max_rws: 256, + max_copy_rows: 256, + max_exp_steps: 256, + max_bytecode: 512, + max_evm_rows: 0, + max_keccak_rows: 0, + }; + let (_, circuit, instance, _) = + SuperCircuit::build(block, circuits_params, Fr::from(0x100)).unwrap(); let instance_refs: Vec<&[Fr]> = instance.iter().map(|v| &v[..]).collect(); // Bench setup generation - let setup_message = format!("Setup generation with degree = {}", degree); + let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); let start1 = start_timer!(|| setup_message); let general_params = ParamsKZG::::setup(degree, &mut rng); let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); @@ -89,7 +107,10 @@ mod tests { let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); // Bench proof generation time - let proof_message = format!("SuperCircuit Proof generation with degree = {}", degree); + let proof_message = format!( + "{} {} with degree = {}", + BENCHMARK_ID, proof_gen_prfx, degree + ); let start2 = start_timer!(|| proof_message); create_proof::< KZGCommitmentScheme, @@ -97,7 +118,7 @@ mod tests { Challenge255, ChaChaRng, Blake2bWrite, G1Affine, Challenge255>, - SuperCircuit, + SuperCircuit, >( &general_params, &pk, @@ -111,7 +132,7 @@ mod tests { end_timer!(start2); // Bench verification time - let start3 = start_timer!(|| "SuperCircuit Proof verification"); + let start3 = start_timer!(|| format!("{} {}", BENCHMARK_ID, proof_ver_prfx)); let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(&proof[..]); let strategy = SingleStrategy::new(&general_params); diff --git a/circuit-benchmarks/src/tx_circuit.rs b/circuit-benchmarks/src/tx_circuit.rs index e9d85ed63a..4aa76da7ad 100644 --- a/circuit-benchmarks/src/tx_circuit.rs +++ b/circuit-benchmarks/src/tx_circuit.rs @@ -4,59 +4,58 @@ mod tests { use ark_std::{end_timer, start_timer}; use env_logger::Env; - use halo2_proofs::halo2curves::CurveAffine; - use halo2_proofs::plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}; - use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}; - use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; - use halo2_proofs::poly::kzg::strategy::SingleStrategy; use halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, - poly::commitment::ParamsProver, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, }; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; - use std::marker::PhantomData; - use zkevm_circuits::tx_circuit::{sign_verify::SignVerifyChip, Curve, TxCircuit}; - use zkevm_circuits::tx_circuit::{Group, Secp256k1Affine}; - - use crate::bench_params::DEGREE; + use std::env::var; + use zkevm_circuits::tx_circuit::TxCircuit; #[cfg_attr(not(feature = "benches"), ignore)] #[test] fn bench_tx_circuit_prover() { env_logger::Builder::from_env(Env::default().default_filter_or("debug")).init(); + let setup_prfx = crate::constants::SETUP_PREFIX; + let proof_gen_prfx = crate::constants::PROOFGEN_PREFIX; + let proof_ver_prfx = crate::constants::PROOFVER_PREFIX; + // Unique string used by bench results module for parsing the result + const BENCHMARK_ID: &str = "Tx Circuit"; // Approximate value, adjust with changes on the TxCircuit. const ROWS_PER_TX: usize = 175_000; - const MAX_TXS: usize = 2_usize.pow(DEGREE as u32) / ROWS_PER_TX; + const MAX_CALLDATA: usize = 1024; + let degree: u32 = var("DEGREE") + .unwrap_or_else(|_| "19".to_string()) + .parse() + .expect("Cannot parse DEGREE env var as u32"); + + let max_txs: usize = 2_usize.pow(degree) / ROWS_PER_TX; + let mut rng = ChaCha20Rng::seed_from_u64(42); - let aux_generator = - ::CurveExt::random(&mut rng).to_affine(); let chain_id: u64 = mock::MOCK_CHAIN_ID.low_u64(); - let txs = vec![mock::CORRECT_MOCK_TXS[0].clone().into()]; - - // SignVerifyChip -> ECDSAChip -> MainGate instance column - let circuit = TxCircuit:: { - sign_verify: SignVerifyChip { - aux_generator, - window_size: 2, - _marker: PhantomData, - }, - txs, - chain_id, - }; + let circuit = TxCircuit::::new(max_txs, MAX_CALLDATA, chain_id, txs); // Bench setup generation - let setup_message = format!("Setup generation with degree = {}", DEGREE); + let setup_message = format!("{} {} with degree = {}", BENCHMARK_ID, setup_prfx, degree); let start1 = start_timer!(|| setup_message); - let general_params = ParamsKZG::::setup(DEGREE as u32, &mut rng); + let general_params = ParamsKZG::::setup(degree, &mut rng); let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); end_timer!(start1); @@ -67,7 +66,10 @@ mod tests { let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); // Bench proof generation time - let proof_message = format!("Tx Circuit Proof generation with degree = {}", DEGREE); + let proof_message = format!( + "{} {} with degree = {}", + BENCHMARK_ID, proof_gen_prfx, degree + ); let start2 = start_timer!(|| proof_message); create_proof::< KZGCommitmentScheme, @@ -75,7 +77,7 @@ mod tests { Challenge255, ChaCha20Rng, Blake2bWrite, G1Affine, Challenge255>, - TxCircuit, + TxCircuit, >( &general_params, &pk, @@ -89,7 +91,7 @@ mod tests { end_timer!(start2); // Bench verification time - let start3 = start_timer!(|| "Tx Circuit Proof verification"); + let start3 = start_timer!(|| format!("{} {}", BENCHMARK_ID, proof_ver_prfx)); let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(&proof[..]); let strategy = SingleStrategy::new(&general_params); diff --git a/eth-types/Cargo.toml b/eth-types/Cargo.toml index e40bc2945f..d0d43f8cfc 100644 --- a/eth-types/Cargo.toml +++ b/eth-types/Cargo.toml @@ -10,7 +10,7 @@ ethers-core = "0.17.0" ethers-signers = "0.17.0" hex = "0.4" lazy_static = "1.4" -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_09_10" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } regex = "1.5.4" serde = {version = "1.0.130", features = ["derive"] } serde_json = "1.0.66" @@ -22,4 +22,8 @@ subtle = "2.4" sha3 = "0.10" num = "0.4" num-bigint = { version = "0.4" } +strum_macros = "0.24" +strum = "0.24" +[features] +warn-unimplemented = [] diff --git a/eth-types/src/bytecode.rs b/eth-types/src/bytecode.rs index 406a9f51a6..a72b30c682 100644 --- a/eth-types/src/bytecode.rs +++ b/eth-types/src/bytecode.rs @@ -1,6 +1,6 @@ //! EVM byte code generator -use crate::{evm_types::OpcodeId, Bytes, Word}; +use crate::{evm_types::OpcodeId, Bytes, ToWord, Word}; use std::{collections::HashMap, str::FromStr}; /// Error type for Bytecode related failures @@ -95,8 +95,9 @@ impl Bytecode { } /// Push - pub fn push(&mut self, n: u8, value: Word) -> &mut Self { + pub fn push(&mut self, n: u8, value: T) -> &mut Self { debug_assert!((1..=32).contains(&n), "invalid push"); + let value = value.to_word(); // Write the op code self.write_op((OpcodeId::push_n(n)).expect("valid push size")); @@ -148,31 +149,6 @@ impl Bytecode { self } - /// Call a contract - #[allow(clippy::too_many_arguments)] - pub fn call( - &mut self, - gas: Word, - address: Word, - value: Word, - mem_in: Word, - mem_in_size: Word, - mem_out: Word, - mem_out_size: Word, - ) -> &mut Self { - self.append(&crate::bytecode! { - PUSH32(mem_out_size) - PUSH32(mem_out) - PUSH32(mem_in_size) - PUSH32(mem_in) - PUSH32(value) - PUSH32(address) - PUSH32(gas) - CALL - }); - self - } - /// Generate the diassembly pub fn disasm(&self) -> String { let mut asm = String::new(); @@ -209,6 +185,12 @@ impl Bytecode { pub fn iter(&self) -> BytecodeIterator<'_> { BytecodeIterator(self.code.iter()) } + + /// JUMPDEST opcode + pub fn op_jumpdest(&mut self) -> usize { + self.write_op(OpcodeId::JUMPDEST); + self.code.len() + } } /// An ASM entry @@ -335,7 +317,7 @@ macro_rules! bytecode_internal { ($code:ident, $x:ident ($v:expr) $($rest:tt)*) => {{ debug_assert!($crate::evm_types::OpcodeId::$x.is_push(), "invalid push"); let n = $crate::evm_types::OpcodeId::$x.postfix().expect("opcode with postfix"); - $code.push(n, $v.into()); + $code.push(n, $v); $crate::bytecode_internal!($code, $($rest)*); }}; // Default opcode without any inputs @@ -350,12 +332,203 @@ macro_rules! bytecode_internal { $crate::bytecode_internal!($code, $($rest)*); }}; // Function calls - ($code:ident, .$function:ident ($($args:expr),*) $($rest:tt)*) => {{ - $code.$function($($args.into(),)*); + ($code:ident, .$function:ident ($($args:expr),* $(,)?) $($rest:tt)*) => {{ + $code.$function($($args,)*); $crate::bytecode_internal!($code, $($rest)*); }}; } +macro_rules! impl_push_n { + ($($push_n:ident, $n:expr)*) => { + #[allow(missing_docs)] + impl Bytecode { + $( + pub fn $push_n(&mut self, value: T) -> &mut Self { + self.push($n, value) + } + )* + } + }; +} + +impl_push_n! { + op_push1, 1 + op_push2, 2 + op_push3, 3 + op_push4, 4 + op_push5, 5 + op_push6, 6 + op_push7, 7 + op_push8, 8 + op_push9, 9 + op_push10, 10 + op_push11, 11 + op_push12, 12 + op_push13, 13 + op_push14, 14 + op_push15, 15 + op_push16, 16 + op_push17, 17 + op_push18, 18 + op_push19, 19 + op_push20, 20 + op_push21, 21 + op_push22, 22 + op_push23, 23 + op_push24, 24 + op_push25, 25 + op_push26, 26 + op_push27, 27 + op_push28, 28 + op_push29, 29 + op_push30, 30 + op_push31, 31 + op_push32, 32 +} + +macro_rules! impl_other_opcodes_inner { + ($self:ident, ) => {}; + ($self:ident, $arg:ident) => { + $self.op_push32($arg); + }; + ($self:ident, $arg:ident $($tail:ident)+) => { + impl_other_opcodes_inner!($self, $($tail)*); + $self.op_push32($arg); + } +} + +macro_rules! impl_other_opcodes { + ($(($op:ident, $x:ident $(, $arg:ident : $arg_ty:ident)*)),* $(,)?) => { + #[allow(missing_docs)] + #[allow(clippy::too_many_arguments)] + impl Bytecode { + $( + pub fn $op<$( + $arg_ty: ToWord, + )*>(&mut self, $($arg: $arg_ty),*) -> &mut Self { + impl_other_opcodes_inner!(self, $($arg)*); + self.write_op($crate::evm_types::OpcodeId::$x) + } + )* + } + }; +} + +impl_other_opcodes! { + (op_stop, STOP), + (op_add, ADD, a: A, b: B), + (op_mul, MUL, a: A, b: B), + (op_sub, SUB, a: A, b: B), + (op_div, DIV, a: A, b: B), + (op_sdiv, SDIV, a: A, b: B), + (op_mod, MOD, a: A, b: B), + (op_smod, SMOD, a: A, b: B), + (op_addmod, ADDMOD, a: A, b: B, n: N), + (op_mulmod, MULMOD, a: A, b: B, n: N), + (op_exp, EXP, a: A, exponent: B), + (op_signextend, SIGNEXTEND, b: A, x: B), + (op_lt, LT, a: A, b: B), + (op_gt, GT, a: A, b: B), + (op_slt, SLT, a: A, b: B), + (op_sgt, SGT, a: A, b: B), + (op_eq, EQ, a: A, b: B), + (op_iszero, ISZERO, a: A), + (op_and, AND, a: A, b: B), + (op_or, OR, a: A, b: B), + (op_xor, XOR, a: A, b: B), + (op_not, NOT, a: A), + (op_byte, BYTE, i: I, x: X), + (op_shl, SHL, shift: S, value: V), + (op_shr, SHR, shift: S, value: V), + (op_sar, SAR, shift: S, value: V), + (op_sha3, SHA3, offset: O, size: S), + (op_address, ADDRESS), + (op_balance, BALANCE, address: A), + (op_origin, ORIGIN), + (op_caller, CALLER), + (op_callvalue, CALLVALUE), + (op_calldataload, CALLDATALOAD, i: I), + (op_calldatasize, CALLDATASIZE), + (op_calldatacopy, CALLDATACOPY, dest_offset: D, offset: B, size: C), + (op_codesize, CODESIZE), + (op_codecopy, CODECOPY, dest_offset: D, offset: B, size: C), + (op_gasprice, GASPRICE), + (op_extcodesize, EXTCODESIZE, address: A), + (op_extcodecopy, EXTCODECOPY, address: A, dest_offset: D, offset: B, size: C), + (op_returndatasize, RETURNDATASIZE), + (op_returndatacopy, RETURNDATACOPY, dest_offset: D, offset: B, size: C), + (op_extcodehash, EXTCODEHASH, address: A), + (op_blockhash, BLOCKHASH, blocknumber: B), + (op_coinbase, COINBASE), + (op_timestamp, TIMESTAMP), + (op_number, NUMBER), + (op_prevrandao, DIFFICULTY), // alias for DIFFICULTY + (op_difficulty, DIFFICULTY), + (op_gaslimit, GASLIMIT), + (op_chainid, CHAINID), + (op_selfbalance, SELFBALANCE), + // (op_basefee, BASEFEE), ignored + (op_pop, POP), + (op_mload, MLOAD, offset: O), + (op_mstore, MSTORE, offset: O, value: V), + (op_mstore8, MSTORE8, offset: O, value: V), + (op_sload, SLOAD, offset: O), + (op_sstore, SSTORE, offset: O, value: V), + (op_jump, JUMP, counter: C), + (op_jumpi, JUMPI, counter: C), // branch not included + (op_pc, PC), + (op_msize, MSIZE), + (op_gas, GAS), + // (op_jumpdest, JUMPDEST), manually implemented + (op_dup1, DUP1), + (op_dup2, DUP2), + (op_dup3, DUP3), + (op_dup4, DUP4), + (op_dup5, DUP5), + (op_dup6, DUP6), + (op_dup7, DUP7), + (op_dup8, DUP8), + (op_dup9, DUP9), + (op_dup10, DUP10), + (op_dup11, DUP11), + (op_dup12, DUP12), + (op_dup13, DUP13), + (op_dup14, DUP14), + (op_dup15, DUP15), + (op_dup16, DUP16), + (op_swap1, SWAP1), + (op_swap2, SWAP2), + (op_swap3, SWAP3), + (op_swap4, SWAP4), + (op_swap5, SWAP5), + (op_swap6, SWAP6), + (op_swap7, SWAP7), + (op_swap8, SWAP8), + (op_swap9, SWAP9), + (op_swap10, SWAP10), + (op_swap11, SWAP11), + (op_swap12, SWAP12), + (op_swap13, SWAP13), + (op_swap14, SWAP14), + (op_swap15, SWAP15), + (op_swap16, SWAP16), + (op_log0, LOG0, offset: O, size: S), + (op_log1, LOG1, offset: O, size: S, topic1: T1), + (op_log2, LOG2, offset: O, size: S, topic1: T1, topic2: T2), + (op_log3, LOG3, offset: O, size: S, topic1: T1, topic2: T2, topic3: T3), + (op_log4, LOG4, offset: O, size: S, topic1: T1, topic2: T2, topic3: T3, topic4: T4), + (op_create, CREATE, value: V, offset: O, size: S), + (op_call, CALL, gas: G, address: A, value: V, args_offset: AO, args_size: AS, ret_offset: RO, ret_size: RS), + (op_callcode, CALLCODE, gas: G, address: A, value: V, args_offset: AO, args_size: AS, ret_offset: RO, ret_size: RS), + (op_return, RETURN, offset: O, size: S), + (op_delegatecall, DELEGATECALL, gas: G, address: A, args_offset: AO, args_size: AS, ret_offset: RO, ret_size: RS), + (op_create2, CREATE2, value: V, offset: O, size: SI, salt: SA), + (op_staticcall, STATICCALL, gas: G, address: A, args_offset: AO, args_size: AS, ret_offset: RO, ret_size: RS), + (op_revert, REVERT, offset: O, size: S), + // (op_invalid, INVALID), ignored + // (op_selfdestruct, SELFDESTRUCT), ignored +} + #[cfg(test)] mod tests { use super::*; diff --git a/eth-types/src/evm_types.rs b/eth-types/src/evm_types.rs index 63733e3445..1dece74eb2 100644 --- a/eth-types/src/evm_types.rs +++ b/eth-types/src/evm_types.rs @@ -9,15 +9,13 @@ pub mod opcode_ids; pub mod stack; pub mod storage; -pub use { - memory::{Memory, MemoryAddress}, - opcode_ids::OpcodeId, - stack::{Stack, StackAddress}, - storage::Storage, -}; +pub use memory::{Memory, MemoryAddress}; +pub use opcode_ids::OpcodeId; +pub use stack::{Stack, StackAddress}; +pub use storage::Storage; /// Wrapper type over `usize` which represents the program counter of the Evm. -#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, PartialOrd, Ord)] +#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, PartialOrd, Ord, Default)] pub struct ProgramCounter(pub usize); impl fmt::Debug for ProgramCounter { @@ -56,21 +54,39 @@ impl ProgramCounter { #[derive(Default, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Gas(pub u64); +impl fmt::Display for Gas { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!("{}", self.0)) + } +} + impl fmt::Debug for Gas { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("{}", self.0)) } } +impl From for u64 { + fn from(value: Gas) -> Self { + value.0 + } +} + /// Quotient for max refund of gas used pub const MAX_REFUND_QUOTIENT_OF_GAS_USED: usize = 5; /// Gas stipend when CALL or CALLCODE is attached with value. pub const GAS_STIPEND_CALL_WITH_VALUE: u64 = 2300; /// Defines the gas consumption. -#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize, Default)] pub struct GasCost(pub u64); +impl fmt::Display for GasCost { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!("{}", self.0)) + } +} + impl fmt::Debug for GasCost { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("{}", self.0)) @@ -98,7 +114,7 @@ impl GasCost { pub const SHA3: Self = Self(30); /// Constant cost for SELFDESTRUCT pub const SELFDESTRUCT: Self = Self(5000); - /// Constant cost for CREATE + /// Constant cost for CREATE and CREATE2 pub const CREATE: Self = Self(32000); /// Constant cost for copying every word pub const COPY: Self = Self(3); @@ -111,6 +127,8 @@ impl GasCost { pub const COLD_SLOAD: Self = Self(2100); /// Constant cost for a cold account access pub const COLD_ACCOUNT_ACCESS: Self = Self(2600); + /// SSTORE reentrancy sentry + pub const SSTORE_SENTRY: Self = Self(2300); /// Constant cost for a storage set pub const SSTORE_SET: Self = Self(20000); /// Constant cost for a storage reset @@ -134,6 +152,9 @@ impl GasCost { pub const MEMORY_EXPANSION_LINEAR_COEFF: Self = Self(3); /// Constant gas for LOG[0-4] op codes pub const LOG: Self = Self(375); + /// Times ceil exponent byte size for the EXP instruction, EIP-158 changed + /// it from 10 to 50. + pub const EXP_BYTE_TIMES: Self = Self(50); } impl GasCost { diff --git a/eth-types/src/evm_types/gas_utils.rs b/eth-types/src/evm_types/gas_utils.rs index d1e032d669..8d34a37e20 100644 --- a/eth-types/src/evm_types/gas_utils.rs +++ b/eth-types/src/evm_types/gas_utils.rs @@ -24,8 +24,14 @@ pub fn memory_copier_gas_cost( num_copy_bytes: u64, ) -> u64 { let num_words = (num_copy_bytes + 31) / 32; - num_words * GasCost::COPY.as_u64() - + memory_expansion_gas_cost(curr_memory_word_size, next_memory_word_size) + num_words * GasCost::COPY.as_u64() + + // Note that opcodes with a byte size parameter of 0 will not trigger + // memory expansion, regardless of their offset parameters. + if num_words > 0 { + memory_expansion_gas_cost(curr_memory_word_size, next_memory_word_size) + } else { + 0 + } } /// Calculate EIP 150 gas passed to callee. diff --git a/eth-types/src/evm_types/memory.rs b/eth-types/src/evm_types/memory.rs index 7935e4185e..ab0e7e5eef 100644 --- a/eth-types/src/evm_types/memory.rs +++ b/eth-types/src/evm_types/memory.rs @@ -1,8 +1,9 @@ //! Doc this -use crate::Error; -use crate::{DebugByte, ToBigEndian, Word}; -use core::ops::{Add, AddAssign, Index, IndexMut, Mul, MulAssign, Range, Sub, SubAssign}; -use core::str::FromStr; +use crate::{DebugByte, Error, ToBigEndian, Word}; +use core::{ + ops::{Add, AddAssign, Index, IndexMut, Mul, MulAssign, Range, Sub, SubAssign}, + str::FromStr, +}; use itertools::Itertools; use serde::{Serialize, Serializer}; use std::fmt; @@ -326,6 +327,41 @@ impl Memory { self.0.resize(memory_size, 0); } } + + /// Copy source data to memory. Used in (ext)codecopy/calldatacopy. + pub fn copy_from(&mut self, dst_offset: Word, src_offset: Word, length: Word, data: &[u8]) { + // Reference go-ethereum `opCallDataCopy` function for defails. + // https://github.com/ethereum/go-ethereum/blob/bb4ac2d396de254898a5f44b1ea2086bfe5bd193/core/vm/instructions.go#L299 + + // `length` should be checked for overflow during gas cost calculation. + // Otherwise should return an out of gas error previously. + let length = length.as_usize(); + if length != 0 { + // `dst_offset` should be within range if length is non-zero. + // https://github.com/ethereum/go-ethereum/blob/bb4ac2d396de254898a5f44b1ea2086bfe5bd193/core/vm/common.go#L37 + let dst_offset = dst_offset.as_u64(); + + // Reset data offset to the maximum value of Uint64 if overflow. + let src_offset = u64::try_from(src_offset).unwrap_or(u64::MAX); + + let minimal_length = dst_offset as usize + length; + self.extend_at_least(minimal_length); + + let mem_starts = dst_offset as usize; + let mem_ends = mem_starts + length; + let dst_slice = &mut self.0[mem_starts..mem_ends]; + dst_slice.fill(0); + let data_starts = src_offset as usize; + let actual_length = std::cmp::min( + length, + data.len().checked_sub(data_starts).unwrap_or_default(), + ); + if actual_length != 0 { + let src_slice = &data[data_starts..data_starts + actual_length]; + dst_slice[..actual_length].copy_from_slice(src_slice); + } + } + } } #[cfg(test)] @@ -349,10 +385,10 @@ mod memory_tests { let first_usize = 64536usize; // Parsing on both ways works. assert_eq!( - MemoryAddress::from_le_bytes(&first_usize.to_le_bytes())?, - MemoryAddress::from_be_bytes(&first_usize.to_be_bytes())? + MemoryAddress::from_le_bytes(first_usize.to_le_bytes())?, + MemoryAddress::from_be_bytes(first_usize.to_be_bytes())? ); - let addr = MemoryAddress::from_le_bytes(&first_usize.to_le_bytes())?; + let addr = MemoryAddress::from_le_bytes(first_usize.to_le_bytes())?; assert_eq!(addr, MemoryAddress::from(first_usize)); // Little endian export diff --git a/eth-types/src/evm_types/opcode_ids.rs b/eth-types/src/evm_types/opcode_ids.rs index 2726f4ab02..d9192fcae4 100644 --- a/eth-types/src/evm_types/opcode_ids.rs +++ b/eth-types/src/evm_types/opcode_ids.rs @@ -4,11 +4,11 @@ use core::fmt::Debug; use lazy_static::lazy_static; use regex::Regex; use serde::{de, Deserialize, Serialize}; -use std::fmt; -use std::str::FromStr; +use std::{fmt, matches, str::FromStr}; +use strum_macros::EnumIter; /// Opcode enum. One-to-one corresponding to an `u8` value. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Hash)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Hash, EnumIter)] pub enum OpcodeId { /// `STOP` STOP, @@ -662,6 +662,168 @@ impl OpcodeId { } } + /// Returns invalid stack pointers of `OpcodeId` + pub fn invalid_stack_ptrs(&self) -> Vec { + let (min_stack_ptr, max_stack_ptr): (u32, u32) = match self { + // `min_stack_pointer` 0 means stack overflow never happen, for example, `OpcodeId::ADD` + // can only encounter underflow error, but never encounter overflow error. + // `max_stack_pointer` means max stack poniter for op code normally run. for example, + // `OpcodeId::ADD` 's max stack pointer is 1022, when actual sp > 1022, will + // encounter underflow error. + OpcodeId::STOP => (0, 1024), + OpcodeId::ADD => (0, 1022), + OpcodeId::MUL => (0, 1022), + OpcodeId::SUB => (0, 1022), + OpcodeId::DIV => (0, 1022), + OpcodeId::SDIV => (0, 1022), + OpcodeId::MOD => (0, 1022), + OpcodeId::SMOD => (0, 1022), + OpcodeId::ADDMOD => (0, 1021), + OpcodeId::MULMOD => (0, 1021), + OpcodeId::EXP => (0, 1022), + OpcodeId::SIGNEXTEND => (0, 1022), + OpcodeId::LT => (0, 1022), + OpcodeId::GT => (0, 1022), + OpcodeId::SLT => (0, 1022), + OpcodeId::SGT => (0, 1022), + OpcodeId::EQ => (0, 1022), + OpcodeId::ISZERO => (0, 1023), + OpcodeId::AND => (0, 1022), + OpcodeId::OR => (0, 1022), + OpcodeId::XOR => (0, 1022), + OpcodeId::NOT => (0, 1023), + OpcodeId::BYTE => (0, 1022), + OpcodeId::SHL => (0, 1022), + OpcodeId::SHR => (0, 1022), + OpcodeId::SAR => (0, 1022), + OpcodeId::SHA3 => (0, 1022), + OpcodeId::ADDRESS => (1, 1024), + OpcodeId::BALANCE => (0, 1023), + OpcodeId::ORIGIN => (1, 1024), + OpcodeId::CALLER => (1, 1024), + OpcodeId::CALLVALUE => (1, 1024), + OpcodeId::CALLDATALOAD => (0, 1023), + OpcodeId::CALLDATASIZE => (1, 1024), + OpcodeId::CALLDATACOPY => (0, 1021), + OpcodeId::CODESIZE => (1, 1024), + OpcodeId::CODECOPY => (0, 1021), + OpcodeId::GASPRICE => (1, 1024), + OpcodeId::EXTCODESIZE => (0, 1023), + OpcodeId::EXTCODECOPY => (0, 1020), + OpcodeId::RETURNDATASIZE => (1, 1024), + OpcodeId::RETURNDATACOPY => (0, 1021), + OpcodeId::EXTCODEHASH => (0, 1023), + OpcodeId::BLOCKHASH => (0, 1023), + OpcodeId::COINBASE => (1, 1024), + OpcodeId::TIMESTAMP => (1, 1024), + OpcodeId::NUMBER => (1, 1024), + OpcodeId::DIFFICULTY => (1, 1024), + OpcodeId::GASLIMIT => (1, 1024), + OpcodeId::CHAINID => (1, 1024), + OpcodeId::SELFBALANCE => (1, 1024), + OpcodeId::BASEFEE => (1, 1024), + OpcodeId::POP => (0, 1023), + OpcodeId::MLOAD => (0, 1023), + OpcodeId::MSTORE => (0, 1022), + OpcodeId::MSTORE8 => (0, 1022), + OpcodeId::SLOAD => (0, 1023), + OpcodeId::SSTORE => (0, 1022), + OpcodeId::JUMP => (0, 1023), + OpcodeId::JUMPI => (0, 1022), + OpcodeId::PC => (1, 1024), + OpcodeId::MSIZE => (1, 1024), + OpcodeId::GAS => (1, 1024), + OpcodeId::JUMPDEST => (0, 1024), + OpcodeId::PUSH1 => (1, 1024), + OpcodeId::PUSH2 => (1, 1024), + OpcodeId::PUSH3 => (1, 1024), + OpcodeId::PUSH4 => (1, 1024), + OpcodeId::PUSH5 => (1, 1024), + OpcodeId::PUSH6 => (1, 1024), + OpcodeId::PUSH7 => (1, 1024), + OpcodeId::PUSH8 => (1, 1024), + OpcodeId::PUSH9 => (1, 1024), + OpcodeId::PUSH10 => (1, 1024), + OpcodeId::PUSH11 => (1, 1024), + OpcodeId::PUSH12 => (1, 1024), + OpcodeId::PUSH13 => (1, 1024), + OpcodeId::PUSH14 => (1, 1024), + OpcodeId::PUSH15 => (1, 1024), + OpcodeId::PUSH16 => (1, 1024), + OpcodeId::PUSH17 => (1, 1024), + OpcodeId::PUSH18 => (1, 1024), + OpcodeId::PUSH19 => (1, 1024), + OpcodeId::PUSH20 => (1, 1024), + OpcodeId::PUSH21 => (1, 1024), + OpcodeId::PUSH22 => (1, 1024), + OpcodeId::PUSH23 => (1, 1024), + OpcodeId::PUSH24 => (1, 1024), + OpcodeId::PUSH25 => (1, 1024), + OpcodeId::PUSH26 => (1, 1024), + OpcodeId::PUSH27 => (1, 1024), + OpcodeId::PUSH28 => (1, 1024), + OpcodeId::PUSH29 => (1, 1024), + OpcodeId::PUSH30 => (1, 1024), + OpcodeId::PUSH31 => (1, 1024), + OpcodeId::PUSH32 => (1, 1024), + OpcodeId::DUP1 => (1, 1023), + OpcodeId::DUP2 => (1, 1022), + OpcodeId::DUP3 => (1, 1021), + OpcodeId::DUP4 => (1, 1020), + OpcodeId::DUP5 => (1, 1019), + OpcodeId::DUP6 => (1, 1018), + OpcodeId::DUP7 => (1, 1017), + OpcodeId::DUP8 => (1, 1016), + OpcodeId::DUP9 => (1, 1015), + OpcodeId::DUP10 => (1, 1014), + OpcodeId::DUP11 => (1, 1013), + OpcodeId::DUP12 => (1, 1012), + OpcodeId::DUP13 => (1, 1011), + OpcodeId::DUP14 => (1, 1010), + OpcodeId::DUP15 => (1, 1009), + OpcodeId::DUP16 => (1, 1008), + OpcodeId::SWAP1 => (0, 1022), + OpcodeId::SWAP2 => (0, 1021), + OpcodeId::SWAP3 => (0, 1020), + OpcodeId::SWAP4 => (0, 1019), + OpcodeId::SWAP5 => (0, 1018), + OpcodeId::SWAP6 => (0, 1017), + OpcodeId::SWAP7 => (0, 1016), + OpcodeId::SWAP8 => (0, 1015), + OpcodeId::SWAP9 => (0, 1014), + + OpcodeId::SWAP10 => (0, 1013), + OpcodeId::SWAP11 => (0, 1012), + OpcodeId::SWAP12 => (0, 1011), + OpcodeId::SWAP13 => (0, 1010), + OpcodeId::SWAP14 => (0, 1009), + OpcodeId::SWAP15 => (0, 1008), + OpcodeId::SWAP16 => (0, 1007), + OpcodeId::LOG0 => (0, 1022), + OpcodeId::LOG1 => (0, 1021), + OpcodeId::LOG2 => (0, 1020), + OpcodeId::LOG3 => (0, 1019), + OpcodeId::LOG4 => (0, 1018), + OpcodeId::CREATE => (0, 1021), + OpcodeId::CALL => (0, 1017), + OpcodeId::CALLCODE => (0, 1017), + OpcodeId::RETURN => (0, 1022), + OpcodeId::DELEGATECALL => (0, 1018), + OpcodeId::CREATE2 => (0, 1020), + OpcodeId::STATICCALL => (0, 1018), + OpcodeId::REVERT => (0, 1022), + OpcodeId::SELFDESTRUCT => (0, 1023), + _ => (0, 0), + }; + + debug_assert!(max_stack_ptr <= 1024); + + (0..min_stack_ptr) + // Range (1025..=1024) is valid and it should be converted to an empty vector. + .chain(max_stack_ptr.checked_add(1).unwrap()..=1024) + .collect() + } + /// Returns `true` if the `OpcodeId` has memory access pub const fn has_memory_access(&self) -> bool { matches!( @@ -709,6 +871,26 @@ impl OpcodeId { 0 } } + + /// Returns the all valid opcodes. + pub fn valid_opcodes() -> Vec { + (u8::MIN..=u8::MAX).fold(vec![], |mut acc, val| { + if !matches!(val.into(), Self::INVALID(_)) { + acc.push(val.into()); + } + acc + }) + } + + /// Returns the all invalid opcodes. + pub fn invalid_opcodes() -> Vec { + (u8::MIN..=u8::MAX).fold(vec![], |mut acc, val| { + if matches!(val.into(), Self::INVALID(_)) { + acc.push(Self::INVALID(val)); + } + acc + }) + } } impl From for OpcodeId { diff --git a/eth-types/src/evm_types/stack.rs b/eth-types/src/evm_types/stack.rs index aac9742e88..ab3a11d69b 100644 --- a/eth-types/src/evm_types/stack.rs +++ b/eth-types/src/evm_types/stack.rs @@ -1,9 +1,7 @@ //! Doc this -use crate::{DebugWord, Word}; -use crate::{Error, ToBigEndian}; +use crate::{DebugWord, Error, ToBigEndian, Word}; use core::str::FromStr; -use serde::ser::SerializeSeq; -use serde::{Deserialize, Serialize, Serializer}; +use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer}; use std::fmt; /// Represents a `StackAddress` of the EVM. @@ -44,7 +42,7 @@ impl FromStr for StackAddress { fn from_str(s: &str) -> Result { let s = s.strip_prefix("0x").unwrap_or(s); let value = usize::from_str_radix(s, 16).map_err(|_| Error::StackAddressParsing)?; - // Stack only has 1023 slots avaliable. + // Stack only has 1023 slots available. if value >= 1024 { return Err(Error::InvalidStackPointer); }; @@ -106,7 +104,7 @@ impl Stack { Stack(words) } - /// Returns the first avaliable/free `StackAddress`. + /// Returns the first available/free `StackAddress`. pub fn stack_pointer(&self) -> StackAddress { // Stack has 1024 slots. // First allocation slot for us in the stack is 1023. @@ -118,7 +116,7 @@ impl Stack { StackAddress::from(1024 - self.0.len()) } - /// Returns the second last filled `StackAddress`. + /// Returns the n-th last filled `StackAddress`. pub fn nth_last_filled(&self, nth: usize) -> StackAddress { StackAddress::from(1024 - self.0.len() + nth) } @@ -128,8 +126,11 @@ impl Stack { self.0.last().cloned().ok_or(Error::InvalidStackPointer) } - /// Returns the second last [`Word`] allocated in the `Stack`. + /// Returns the n-th last [`Word`] allocated in the `Stack`. pub fn nth_last(&self, nth: usize) -> Result { + if self.0.len() < (nth + 1) { + return Err(Error::InvalidStackPointer); + } self.0 .get(self.0.len() - (nth + 1)) .cloned() diff --git a/eth-types/src/evm_types/storage.rs b/eth-types/src/evm_types/storage.rs index 9f398b742b..86a1f63455 100644 --- a/eth-types/src/evm_types/storage.rs +++ b/eth-types/src/evm_types/storage.rs @@ -1,10 +1,7 @@ //! Doc this -use crate::{DebugWord, Word}; -use crate::{Error, ToBigEndian}; -use serde::ser::SerializeMap; -use serde::{Serialize, Serializer}; -use std::collections::HashMap; -use std::fmt; +use crate::{DebugWord, Error, ToBigEndian, Word}; +use serde::{ser::SerializeMap, Serialize, Serializer}; +use std::{collections::HashMap, fmt}; /// Represents a snapshot of the EVM stack state at a certain /// execution step height. diff --git a/eth-types/src/geth_types.rs b/eth-types/src/geth_types.rs index 9c6d155e95..5756d29a8c 100644 --- a/eth-types/src/geth_types.rs +++ b/eth-types/src/geth_types.rs @@ -3,9 +3,12 @@ use crate::{ sign_types::{biguint_to_32bytes_le, ct_option_ok_or, recover_pk, SignData, SECP256K1_Q}, AccessList, Address, Block, Bytes, Error, GethExecTrace, Hash, ToBigEndian, ToLittleEndian, - Word, U64, + ToWord, Word, U64, +}; +use ethers_core::{ + types::{transaction::response, NameOrAddress, TransactionRequest}, + utils::get_contract_address, }; -use ethers_core::types::TransactionRequest; use ethers_signers::{LocalWallet, Signer}; use halo2_proofs::halo2curves::{group::ff::PrimeField, secp256k1}; use num::Integer; @@ -21,8 +24,9 @@ use std::collections::HashMap; pub struct Account { /// Address pub address: Address, - /// nonce - pub nonce: Word, + /// Nonce. + /// U64 type is required to serialize into proper hex with 0x prefix + pub nonce: U64, /// Balance pub balance: Word, /// EVM Code @@ -32,6 +36,16 @@ pub struct Account { pub storage: HashMap, } +impl Account { + /// Return if account is empty or not. + pub fn is_empty(&self) -> bool { + self.nonce.is_zero() + && self.balance.is_zero() + && self.code.is_empty() + && self.storage.is_empty() + } +} + fn serde_account_storage( to_serialize: &HashMap, serializer: S, @@ -51,7 +65,8 @@ pub struct BlockConstants { pub coinbase: Address, /// time pub timestamp: Word, - /// number + /// Block number + /// U64 type is required to serialize into proper hex with 0x prefix pub number: U64, /// difficulty pub difficulty: Word, @@ -103,11 +118,14 @@ pub struct Transaction { /// Sender address pub from: Address, /// Recipient address (None for contract creation) + /// Avoid direct read from this field. We set this field public to construct the struct pub to: Option
, /// Transaction nonce - pub nonce: Word, + /// U64 type is required to serialize into proper hex with 0x prefix + pub nonce: U64, /// Gas Limit / Supplied gas - pub gas_limit: Word, + /// U64 type is required to serialize into proper hex with 0x prefix + pub gas_limit: U64, /// Transfered value pub value: Word, /// Gas Price @@ -136,8 +154,8 @@ impl From<&Transaction> for crate::Transaction { crate::Transaction { from: tx.from, to: tx.to, - nonce: tx.nonce, - gas: tx.gas_limit, + nonce: tx.nonce.to_word(), + gas: tx.gas_limit.to_word(), value: tx.value, gas_price: Some(tx.gas_price), max_priority_fee_per_gas: Some(tx.gas_fee_cap), @@ -157,8 +175,8 @@ impl From<&crate::Transaction> for Transaction { Transaction { from: tx.from, to: tx.to, - nonce: tx.nonce, - gas_limit: tx.gas, + nonce: tx.nonce.as_u64().into(), + gas_limit: tx.gas.as_u64().into(), value: tx.value, gas_price: tx.gas_price.unwrap_or_default(), gas_fee_cap: tx.max_priority_fee_per_gas.unwrap_or_default(), @@ -174,14 +192,16 @@ impl From<&crate::Transaction> for Transaction { impl From<&Transaction> for TransactionRequest { fn from(tx: &Transaction) -> TransactionRequest { - TransactionRequest::new() - .from(tx.from) - .to(tx.to.unwrap()) - .nonce(tx.nonce) - .value(tx.value) - .data(tx.call_data.clone()) - .gas(tx.gas_limit) - .gas_price(tx.gas_price) + TransactionRequest { + from: Some(tx.from), + to: tx.to.map(NameOrAddress::Address), + gas: Some(tx.gas_limit.to_word()), + gas_price: Some(tx.gas_price), + value: Some(tx.value), + data: Some(tx.call_data.clone()), + nonce: Some(tx.nonce.to_word()), + ..Default::default() + } } } @@ -206,7 +226,10 @@ impl Transaction { .to_vec() .try_into() .expect("hash length isn't 32 bytes"); - let v = (self.v - 35 - chain_id * 2) as u8; + let v = self + .v + .checked_sub(35 + chain_id * 2) + .ok_or(Error::Signature(libsecp256k1::Error::InvalidSignature))? as u8; let pk = recover_pk(v, &self.r, &self.s, &msg_hash)?; // msg_hash = msg_hash % q let msg_hash = BigUint::from_bytes_be(msg_hash.as_slice()); @@ -222,6 +245,53 @@ impl Transaction { msg_hash, }) } + + /// Compute call data gas cost from call data + pub fn call_data_gas_cost(&self) -> u64 { + self.call_data + .iter() + .fold(0, |acc, byte| acc + if *byte == 0 { 4 } else { 16 }) + } + + /// Get the "to" address. If `to` is None then zero adddress + pub fn to_or_zero(&self) -> Address { + self.to.unwrap_or_default() + } + /// Get the "to" address. If `to` is None then compute contract adddress + pub fn to_or_contract_addr(&self) -> Address { + self.to + .unwrap_or_else(|| get_contract_address(self.from, self.nonce.to_word())) + } + /// Determine if this transaction is a contract create transaction + pub fn is_create(&self) -> bool { + self.to.is_none() + } + + /// Convert to transaction response + pub fn to_response( + &self, + transaction_index: U64, + chain_id: Word, + block_number: U64, + ) -> response::Transaction { + response::Transaction { + from: self.from, + to: self.to, + value: self.value, + input: self.call_data.clone(), + gas_price: Some(self.gas_price), + access_list: self.access_list.clone(), + nonce: self.nonce.to_word(), + gas: self.gas_limit.to_word(), + transaction_index: Some(transaction_index), + r: self.r, + s: self.s, + v: U64::from(self.v), + block_number: Some(block_number), + chain_id: Some(chain_id), + ..response::Transaction::default() + } + } } /// GethData is a type that contains all the information of a Ethereum block diff --git a/eth-types/src/lib.rs b/eth-types/src/lib.rs index 169bdc68aa..e3417d6e50 100644 --- a/eth-types/src/lib.rs +++ b/eth-types/src/lib.rs @@ -1,8 +1,6 @@ //! Ethereum and Evm types used to deserialize responses from web3 / geth. #![cfg_attr(docsrs, feature(doc_cfg))] -// Temporary until we have more of the crate implemented. -#![allow(dead_code)] // We want to have UPPERCASE idents sometimes. #![allow(non_snake_case)] // Catch documentation errors caused by code changes. @@ -24,31 +22,48 @@ pub mod sign_types; pub use bytecode::Bytecode; pub use error::Error; -use halo2_proofs::{ - arithmetic::{Field as Halo2Field, FieldExt}, - halo2curves::{ - bn256::{Fq, Fr}, - group::ff::PrimeField, - }, +use halo2_proofs::halo2curves::{ + bn256::{Fq, Fr}, + ff::{Field as Halo2Field, FromUniformBytes, PrimeField}, }; -use crate::evm_types::{memory::Memory, stack::Stack, storage::Storage}; -use crate::evm_types::{Gas, GasCost, OpcodeId, ProgramCounter}; -pub use ethers_core::abi::ethereum_types::U512; +use crate::evm_types::{ + memory::Memory, stack::Stack, storage::Storage, Gas, GasCost, OpcodeId, ProgramCounter, +}; use ethers_core::types; -pub use ethers_core::types::{ - transaction::{eip2930::AccessList, response::Transaction}, - Address, Block, Bytes, Signature, H160, H256, H64, U256, U64, +pub use ethers_core::{ + abi::ethereum_types::{BigEndianHash, U512}, + types::{ + transaction::{eip2930::AccessList, response::Transaction}, + Address, Block, Bytes, Signature, H160, H256, H64, U256, U64, + }, }; use serde::{de, Deserialize, Serialize}; -use std::collections::HashMap; -use std::fmt; -use std::str::FromStr; +use std::{collections::HashMap, fmt, str::FromStr}; -/// Trait used to reduce verbosity with the declaration of the [`FieldExt`] +/// Trait used to reduce verbosity with the declaration of the [`PrimeField`] /// trait and its repr. -pub trait Field: FieldExt + Halo2Field + PrimeField {} +pub trait Field: Halo2Field + PrimeField + FromUniformBytes<64> + Ord { + /// Gets the lower 128 bits of this field element when expressed + /// canonically. + fn get_lower_128(&self) -> u128 { + let bytes = self.to_repr(); + bytes[..16] + .iter() + .rev() + .fold(0u128, |acc, value| acc * 256u128 + *value as u128) + } + /// Gets the lower 32 bits of this field element when expressed + /// canonically. + fn get_lower_32(&self) -> u32 { + let bytes = self.to_repr(); + bytes[..4] + .iter() + .rev() + .fold(0u32, |acc, value| acc * 256u32 + *value as u32) + } +} // Impl custom `Field` trait for BN256 Fr to be used and consistent with the // rest of the workspace. @@ -195,6 +210,49 @@ impl ToWord for bool { } } +impl ToWord for u64 { + fn to_word(&self) -> Word { + Word::from(*self) + } +} + +impl ToWord for u128 { + fn to_word(&self) -> Word { + Word::from(*self) + } +} + +impl ToWord for usize { + fn to_word(&self) -> Word { + u64::try_from(*self) + .expect("usize bigger than u64") + .to_word() + } +} + +impl ToWord for i32 { + fn to_word(&self) -> Word { + let value = Word::from(self.unsigned_abs() as u64); + if self.is_negative() { + value.overflowing_neg().0 + } else { + value + } + } +} + +impl ToWord for U64 { + fn to_word(&self) -> Word { + self.as_u64().into() + } +} + +impl ToWord for Word { + fn to_word(&self) -> Word { + *self + } +} + impl ToScalar for Address { fn to_scalar(&self) -> Option { let mut bytes = [0u8; 32]; @@ -210,6 +268,18 @@ impl ToScalar for bool { } } +impl ToScalar for u64 { + fn to_scalar(&self) -> Option { + Some(F::from(*self)) + } +} + +impl ToScalar for usize { + fn to_scalar(&self) -> Option { + u64::try_from(*self).ok().map(F::from) + } +} + /// Struct used to define the storage proof #[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize)] pub struct StorageProof { @@ -232,7 +302,7 @@ pub struct EIP1186ProofResponse { /// The hash of the code of the account pub code_hash: H256, /// The nonce of the account - pub nonce: U256, + pub nonce: U64, /// SHA3 of the StorageRoot pub storage_hash: H256, /// Array of rlp-serialized MerkleTree-Nodes @@ -420,8 +490,7 @@ macro_rules! word_map { #[cfg(test)] mod tests { use super::*; - use crate::evm_types::opcode_ids::OpcodeId; - use crate::evm_types::{memory::Memory, stack::Stack}; + use crate::evm_types::{memory::Memory, opcode_ids::OpcodeId, stack::Stack}; #[test] fn deserialize_geth_exec_trace2() { @@ -562,8 +631,7 @@ mod tests { #[cfg(test)] mod eth_types_test { use super::*; - use crate::Error; - use crate::Word; + use crate::{Error, Word}; use std::str::FromStr; #[test] @@ -647,4 +715,16 @@ mod eth_types_test { assert_eq!(word_from_u128, word_from_str); Ok(()) } + + #[test] + fn creation_tx_into_tx_req() -> Result<(), Error> { + let tx = &geth_types::Transaction { + to: None, + ..Default::default() + }; + + let req: ethers_core::types::TransactionRequest = tx.into(); + assert_eq!(req.to, None); + Ok(()) + } } diff --git a/eth-types/src/macros.rs b/eth-types/src/macros.rs index 2fbf9a0aae..7dead60fd0 100644 --- a/eth-types/src/macros.rs +++ b/eth-types/src/macros.rs @@ -203,3 +203,23 @@ macro_rules! define_range_index_variants { } }; } + +/// Triggers a signal that a feature is unimplemented, warns if +/// `warn-unimplemented` feature is set +#[cfg(feature = "warn-unimplemented")] +#[macro_export] +macro_rules! evm_unimplemented { + ($($arg:tt)+) => { + log::warn!("evm_unimplemented: {}", format_args!($($arg)+)) + }; +} + +/// Triggers a signal that a feature is unimplemented, panics if +/// `warn-unimplemented` feature is not set +#[cfg(not(feature = "warn-unimplemented"))] +#[macro_export] +macro_rules! evm_unimplemented { + ($($arg:tt)+) => { + (|| panic!("evm_unimplemented: {}",format_args!($($arg)+)))() + }; +} diff --git a/eth-types/src/sign_types.rs b/eth-types/src/sign_types.rs index f6bee6980b..49df1b1531 100644 --- a/eth-types/src/sign_types.rs +++ b/eth-types/src/sign_types.rs @@ -2,10 +2,10 @@ use crate::{ToBigEndian, Word}; use halo2_proofs::{ - arithmetic::{CurveAffine, FieldExt}, + arithmetic::{CurveAffine, Field}, halo2curves::{ group::{ - ff::{Field as GroupField, PrimeField}, + ff::{FromUniformBytes, PrimeField}, Curve, }, secp256k1::{self, Secp256k1Affine}, @@ -36,7 +36,7 @@ pub fn sign( let mut x_bytes = [0u8; 64]; x_bytes[..32].copy_from_slice(&x_repr[..]); - let sig_r = secp256k1::Fq::from_bytes_wide(&x_bytes); // get x cordinate (E::Base) on E::Scalar + let sig_r = secp256k1::Fq::from_uniform_bytes(&x_bytes); // get x cordinate (E::Base) on E::Scalar let sig_s = randomness_inv * (msg_hash + sig_r * sk); (sig_r, sig_s) } @@ -56,11 +56,11 @@ pub struct SignData { lazy_static! { static ref SIGN_DATA_DEFAULT: SignData = { let generator = Secp256k1Affine::generator(); - let sk = secp256k1::Fq::one(); + let sk = secp256k1::Fq::ONE; let pk = generator * sk; let pk = pk.to_affine(); - let msg_hash = secp256k1::Fq::one(); - let randomness = secp256k1::Fq::one(); + let msg_hash = secp256k1::Fq::ONE; + let randomness = secp256k1::Fq::ONE; let (sig_r, sig_s) = sign(randomness, sk, msg_hash); SignData { @@ -123,7 +123,7 @@ pub fn recover_pk( lazy_static! { /// Secp256k1 Curve Scalar. Referece: Section 2.4.1 (parameter `n`) in "SEC 2: Recommended /// Elliptic Curve Domain Parameters" document at http://www.secg.org/sec2-v2.pdf - pub static ref SECP256K1_Q: BigUint = BigUint::from_bytes_le(&(secp256k1::Fq::zero() - secp256k1::Fq::one()).to_repr()) + 1u64; + pub static ref SECP256K1_Q: BigUint = BigUint::from_bytes_le(&(secp256k1::Fq::ZERO - secp256k1::Fq::ONE).to_repr()) + 1u64; } /// Helper function to convert a `CtOption` into an `Result`. Similar to diff --git a/gadgets/Cargo.toml b/gadgets/Cargo.toml index 3e72f464c5..be8bf9d550 100644 --- a/gadgets/Cargo.toml +++ b/gadgets/Cargo.toml @@ -6,7 +6,7 @@ authors = ["The appliedzkp team"] license = "MIT OR Apache-2.0" [dependencies] -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_09_10" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } sha3 = "0.7.2" eth-types = { path = "../eth-types" } digest = "0.7.6" diff --git a/gadgets/src/batched_is_zero.rs b/gadgets/src/batched_is_zero.rs new file mode 100644 index 0000000000..6f4ff461a9 --- /dev/null +++ b/gadgets/src/batched_is_zero.rs @@ -0,0 +1,256 @@ +//! BatchedIsZero chip works as follows: +//! +//! Given a list of `values` to be checked if they are all zero: +//! - nonempty_witness = `inv(value)` for some non-zero `value` from `values` if it exists, `0` +//! otherwise +//! - is_zero: 1 if all `values` are `0`, `0` otherwise + +use eth_types::Field; +use halo2_proofs::{ + circuit::{Region, Value}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Phase, VirtualCells}, + poly::Rotation, +}; +use std::marker::PhantomData; + +use crate::util::Expr; + +// TODO: Configurable Phase + +/// BatchedIsZeroChip configuration +#[derive(Clone, Debug)] +pub struct BatchedIsZeroConfig { + /// All the values are 0 + pub is_zero: Column, + /// If some value is non-zero, this is its inverse + pub nonempty_witness: Column, +} + +impl BatchedIsZeroConfig { + /// Annotates columns of this gadget embedded within a circuit region. + pub fn annotate_columns_in_region(&self, region: &mut Region, prefix: &str) { + [ + (self.is_zero, "GADGETS_BATCHED_IS_ZERO_is_zero"), + ( + self.nonempty_witness, + "GADGETS_BATCHED_IS_ZERO_nonempty_witness", + ), + ] + .iter() + .for_each(|(col, ann)| region.name_column(|| format!("{}_{}", prefix, ann), *col)); + } +} + +/// Verify that a list of values are all 0. +pub struct BatchedIsZeroChip { + config: BatchedIsZeroConfig, + _marker: PhantomData, +} + +impl BatchedIsZeroChip { + /// Configure the BatchedIsZeroChip + pub fn configure( + meta: &mut ConstraintSystem, + // Phases for is_zero and nonempty_witness advice columns. + (phase_a, phase_b): (P, P), // TODO: Remove once Phase is Copy + q_enable: impl Fn(&mut VirtualCells<'_, F>) -> Expression, + values: impl Fn(&mut VirtualCells<'_, F>) -> [Expression; N], + ) -> BatchedIsZeroConfig { + let is_zero = meta.advice_column_in(phase_a); + let nonempty_witness = meta.advice_column_in(phase_b); + meta.create_gate("is_zero is bool", |meta| { + let is_zero = meta.query_advice(is_zero, Rotation::cur()); + [q_enable(meta) * is_zero.clone() * (is_zero - 1.expr())] + }); + + meta.create_gate("is_zero is 0 if there is any non-zero value", |meta| { + let is_zero = meta.query_advice(is_zero, Rotation::cur()); + values(meta) + .iter() + .map(|value| q_enable(meta) * is_zero.clone() * value.clone()) + .collect::>() + }); + + meta.create_gate("is_zero is 1 if values are all zero", |meta| { + let is_zero = meta.query_advice(is_zero, Rotation::cur()); + let nonempty_witness = meta.query_advice(nonempty_witness, Rotation::cur()); + [q_enable(meta) + * values(meta).iter().fold(1.expr() - is_zero, |acc, value| { + acc * (1.expr() - value.clone() * nonempty_witness.clone()) + })] + }); + + BatchedIsZeroConfig { + is_zero, + nonempty_witness, + } + } + + /// Assign the BatchedIsZeroChip + pub fn assign( + &self, + region: &mut Region<'_, F>, + offset: usize, + values: Value<[F; N]>, + ) -> Result<(), Error> { + let config = &self.config; + let is_zero_nonempty_witness = values.map(|values| { + if let Some(inverse) = values + .iter() + .find_map(|value| Option::::from(value.invert())) + { + (F::ZERO, inverse) + } else { + (F::ONE, F::ZERO) + } + }); + + region.assign_advice( + || "is_zero", + config.is_zero, + offset, + || is_zero_nonempty_witness.map(|v| v.0), + )?; + region.assign_advice( + || "nonempty_witness", + config.nonempty_witness, + offset, + || is_zero_nonempty_witness.map(|v| v.1), + )?; + Ok(()) + } + + /// Given an `BatchedIsZeroConfig`, construct the chip. + pub fn construct(config: BatchedIsZeroConfig) -> Self { + BatchedIsZeroChip { + config, + _marker: PhantomData, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + dev::MockProver, + halo2curves::bn256::Fr, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, FirstPhase, Selector}, + poly::Rotation, + }; + + #[derive(Clone, Debug)] + struct TestCircuitConfig { + q_enable: Selector, + values: [Column; N], + is_zero: BatchedIsZeroConfig, + expect_is_zero: Column, + } + + #[derive(Default)] + struct TestCircuit { + values: Option<[u64; N]>, + expect_is_zero: Option, + _marker: PhantomData, + } + + impl Circuit for TestCircuit { + type Config = TestCircuitConfig; + type FloorPlanner = SimpleFloorPlanner; + type Params = (); + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let q_enable = meta.complex_selector(); + let values = [(); N].map(|_| meta.advice_column()); + let expect_is_zero = meta.advice_column(); + + let is_zero = BatchedIsZeroChip::configure( + meta, + (FirstPhase, FirstPhase), + |meta| meta.query_selector(q_enable), + |meta| values.map(|value| meta.query_advice(value, Rotation::cur())), + ); + + let config = Self::Config { + q_enable, + values, + expect_is_zero, + is_zero, + }; + + meta.create_gate("check is_zero", |meta| { + let q_enable = meta.query_selector(q_enable); + + // This verifies is_zero is calculated correctly + let expect_is_zero = meta.query_advice(config.expect_is_zero, Rotation::cur()); + let is_zero = meta.query_advice(config.is_zero.is_zero, Rotation::cur()); + vec![q_enable * (is_zero - expect_is_zero)] + }); + + config + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let is_zero = BatchedIsZeroChip::construct(config.is_zero); + + let values: [F; N] = self + .values + .as_ref() + .map(|values| values.map(|value| F::from(value))) + .ok_or(Error::Synthesis)?; + let expect_is_zero = self.expect_is_zero.as_ref().ok_or(Error::Synthesis)?; + + layouter.assign_region( + || "witness", + |mut region| { + config.q_enable.enable(&mut region, 0)?; + region.assign_advice( + || "expect_is_zero", + config.expect_is_zero, + 0, + || Value::known(F::from(*expect_is_zero as u64)), + )?; + for (value_column, value) in config.values.iter().zip(values.iter()) { + region.assign_advice( + || "value", + *value_column, + 0, + || Value::known(*value), + )?; + } + is_zero.assign(&mut region, 0, Value::known(values))?; + Ok(()) + }, + ) + } + } + + fn test_circuit(values: [u64; N], expect_is_zero: bool) { + let circuit = TestCircuit:: { + values: Some(values), + expect_is_zero: Some(expect_is_zero), + _marker: PhantomData, + }; + let k = 4; + let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); + prover.assert_satisfied_par() + } + + #[test] + fn test_batched_is_zero() { + test_circuit([0, 0], true); + test_circuit([0, 0, 0], true); + test_circuit([1, 0], false); + test_circuit([1, 0, 0], false); + test_circuit([1, 0, 8], false); + } +} diff --git a/gadgets/src/binary_number.rs b/gadgets/src/binary_number.rs index e11ce5fe94..cb5099504b 100644 --- a/gadgets/src/binary_number.rs +++ b/gadgets/src/binary_number.rs @@ -9,8 +9,7 @@ use halo2_proofs::{ plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, poly::Rotation, }; -use std::collections::BTreeSet; -use std::marker::PhantomData; +use std::{collections::BTreeSet, marker::PhantomData}; use strum::IntoEnumIterator; /// Helper trait that implements functionality to represent a generic type as @@ -92,14 +91,25 @@ where }), ) } + + /// Annotates columns of this gadget embedded within a circuit region. + pub fn annotate_columns_in_region(&self, region: &mut Region, prefix: &str) { + let mut annotations = Vec::new(); + for (i, _) in self.bits.iter().enumerate() { + annotations.push(format!("GADGETS_binary_number_{}", i)); + } + self.bits + .iter() + .zip(annotations.iter()) + .for_each(|(col, ann)| region.name_column(|| format!("{}_{}", prefix, ann), *col)); + } } /// This chip helps working with binary encoding of integers of length N bits /// by: -/// - enforcing that the binary representation is in the valid range defined by -/// T. -/// - creating expressions (via the Config) that evaluate to 1 when the bits -/// match a specific value and 0 otherwise. +/// - enforcing that the binary representation is in the valid range defined by T. +/// - creating expressions (via the Config) that evaluate to 1 when the bits match a specific value +/// and 0 otherwise. #[derive(Clone, Debug)] pub struct BinaryNumberChip { config: BinaryNumberConfig, @@ -180,7 +190,7 @@ where || format!("binary number {:?}", column), column, offset, - || Value::known(F::from(bit)), + || Value::known(F::from(bit as u64)), )?; } Ok(()) diff --git a/gadgets/src/evm_word.rs b/gadgets/src/evm_word.rs deleted file mode 100644 index 5b58ff735a..0000000000 --- a/gadgets/src/evm_word.rs +++ /dev/null @@ -1,278 +0,0 @@ -//! An EVM word (256 bits) is represented as a linear combination of 32 bytes: -//! `encode(word) = b_0 + r * b_1 + ... + r^{31} * b_{31}`, -//! where `word` is a 256-bit word, b_i's are bytes, and `r` is a random factor. -//! This helper returns an expression of `encode(word)`. -//! -//! In the zkevm circuit, this `encode(word)` expression will not be directly -//! looked up. Instead, it will be folded into the bus mapping lookup. - -use crate::Variable; -use digest::{FixedOutput, Input}; -use eth_types::Field; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector}, - poly::Rotation, -}; -use sha3::{Digest, Keccak256}; - -#[cfg(test)] -use halo2_proofs::circuit::Layouter; - -// TODO: Move into crate-level `constants` file. -/// r = hash([0, 1, ..., 255]) -pub fn r() -> F { - let mut hasher = Keccak256::new(); - for byte in 0..=u8::MAX { - hasher.process(&[byte]); - } - let mut r = [0; 64]; - r[..32].copy_from_slice(hasher.fixed_result().as_slice()); - F::from_bytes_wide(&r) -} - -/// Returns encoding of big-endian representation of a 256-bit word. -pub fn encode(vals: impl Iterator, r: F) -> F { - vals.fold(F::zero(), |acc, val| { - let byte = F::from(val as u64); - acc * r + byte - }) -} - -/// A 256-bit word represented in the circuit as 32 bytes. -pub struct Word([Variable; 32]); - -#[allow(dead_code)] -/// Configuration structure used to constraint. generate and assign an EVM Word -/// inside a circuit. -#[derive(Clone, Debug)] -pub struct WordConfig { - /// Randomness used to compress the word encoding. - r: F, - /// Selector to toggle the word encoding gate. - // TODO: This may be replaced by a synthetic selector. - q_encode: Selector, - /// Advice columns used to witness the byte representation of the word. - bytes: [Column; 32], - /// Fixed column containing all possible 8-bit values. This is used in - /// a lookup argument to range-constrain each byte. - byte_lookup: Column, - /// Expression representing `encode(word)`. - encode_word_expr: Expression, -} - -impl WordConfig { - /// Sets up the configuration of the config by creating the required columns - /// & selectors and defining the constraints that take part when using a - /// Word. - pub fn configure( - meta: &mut ConstraintSystem, - r: F, - q_encode: Selector, - bytes: [Column; 32], - byte_lookup: Column, - ) -> Self { - // Expression representing `encode(word)`. - let mut encode_word_expr = Expression::Constant(F::zero()); - - // Lookup each byte in the witnessed word representation to - // range-constrain it to 8 bits. - // - // TODO: Understand why the `for` loop cannot be moved into - // the meta.lookup_any() call. - for byte in bytes.iter().rev() { - meta.lookup_any("Word byte for range", |meta| { - let q_encode = meta.query_selector(q_encode); - let r = Expression::Constant(r); - let byte = meta.query_advice(*byte, Rotation::cur()); - let byte_lookup = meta.query_fixed(byte_lookup, Rotation::cur()); - - // Update encode_word_expr. - encode_word_expr = encode_word_expr.clone() * r + byte.clone(); - - vec![(q_encode * byte, byte_lookup)] - }); - } - - Self { - r, - q_encode, - bytes, - byte_lookup, - encode_word_expr, - } - } - - /// Loads the 8-bit lookup table. - /// NB: This is only used in tests, since the zkevm circuit will load a - /// global 8-bit table. - #[cfg(test)] - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "8-bit table", - |mut meta| { - for byte in 0..=u8::MAX { - meta.assign_fixed( - || format!("load {}", byte), - self.byte_lookup, - byte.into(), - || Value::known(F::from(byte as u64)), - )?; - } - - Ok(()) - }, - ) - } - - /// Assigns the byte decomposition of a word to the `bytes` advice columns. - pub fn assign_word( - &self, - region: &mut Region<'_, F>, - offset: usize, - word: [Value; 32], - ) -> Result, Error> { - let mut bytes: Vec> = Vec::with_capacity(32); - - for (idx, (byte, column)) in word.iter().zip(self.bytes.iter()).enumerate() { - // TODO: We will likely enable this selector outside of the helper. - self.q_encode.enable(region, offset)?; - - let byte_field_elem = byte.map(|byte| F::from(byte as u64)); - let cell = region.assign_advice( - || format!("assign byte {}", idx), - *column, - offset, - || byte_field_elem, - )?; - - bytes.push(Variable::new(cell, *byte)); - } - - Ok(Word(bytes.try_into().unwrap())) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use halo2_proofs::{ - arithmetic::Field as Halo2Field, - circuit::SimpleFloorPlanner, - dev::{FailureLocation, MockProver, VerifyFailure}, - halo2curves::{bn256::Fr as Fp, group::ff::PrimeField}, - plonk::{Circuit, Instance}, - }; - use rand::SeedableRng; - use rand_xorshift::XorShiftRng; - use std::marker::PhantomData; - - #[test] - fn evm_word() { - #[derive(Default)] - struct MyCircuit { - word: [Value; 32], - _marker: PhantomData, - } - - impl Circuit for MyCircuit { - // Introduce an additional instance column here to test lookups - // with public inputs. This is analogous to the bus mapping - // commitment which will be provided as public inputs. - type Config = (WordConfig, Column); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let r = r(); - - let q_encode = meta.complex_selector(); - - let bytes: [Column; 32] = (0..32) - .map(|_| meta.advice_column()) - .collect::>() - .try_into() - .unwrap(); - let byte_lookup = meta.fixed_column(); - - let config = WordConfig::configure(meta, r, q_encode, bytes, byte_lookup); - - let pub_inputs = meta.instance_column(); - - // Make sure each encoded word has been committed to in the - // public inputs. - meta.lookup_any("Encoded word / Pub inputs", |meta| { - let q_encode = meta.query_selector(q_encode); - let pub_inputs = meta.query_instance(pub_inputs, Rotation::cur()); - - let encode_word = config.clone().encode_word_expr; - - vec![(q_encode * encode_word, pub_inputs)] - }); - - (config, pub_inputs) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - config.0.load(&mut layouter)?; - - layouter.assign_region( - || "assign word", - |mut region| { - let offset = 0; - config.0.assign_word(&mut region, offset, self.word) - }, - )?; - - Ok(()) - } - } - - { - let rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - let word = Fp::random(rng); - let circuit = MyCircuit:: { - word: word - .to_repr() - .iter() - .map(|b| Value::known(*b)) - .collect::>() - .try_into() - .unwrap(), - _marker: PhantomData, - }; - - // Test without public inputs - let prover = MockProver::::run(9, &circuit, vec![vec![]]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - name: "Encoded word / Pub inputs", - lookup_index: 32, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from(( - 1, - "assign word".to_string() - )), - offset: 0 - } - }]) - ); - - // Calculate word commitment and use it as public input. - let encoded: Fp = encode(word.to_repr().iter().rev().cloned(), r()); - let prover = MockProver::::run(9, &circuit, vec![vec![encoded]]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - } -} diff --git a/gadgets/src/is_zero.rs b/gadgets/src/is_zero.rs index ebb4ccc5f9..be552b1f89 100644 --- a/gadgets/src/is_zero.rs +++ b/gadgets/src/is_zero.rs @@ -6,7 +6,6 @@ use eth_types::Field; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Chip, Region, Value}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, poly::Rotation, @@ -16,10 +15,9 @@ use crate::util::Expr; /// Trait that needs to be implemented for any gadget or circuit that wants to /// implement `IsZero`. -pub trait IsZeroInstruction { +pub trait IsZeroInstruction { /// Given a `value` to be checked if it is zero: - /// - witnesses `inv0(value)`, where `inv0(x)` is 0 when `x` = 0, and - /// `1/x` otherwise + /// - witnesses `inv0(value)`, where `inv0(x)` is 0 when `x` = 0, and `1/x` otherwise fn assign( &self, region: &mut Region<'_, F>, @@ -39,18 +37,25 @@ pub struct IsZeroConfig { pub is_zero_expression: Expression, } -impl IsZeroConfig { +impl IsZeroConfig { /// Returns the is_zero expression pub fn expr(&self) -> Expression { self.is_zero_expression.clone() } + + /// Annotates columns of this gadget embedded within a circuit region. + pub fn annotate_columns_in_region(&self, region: &mut Region, prefix: &str) { + [(self.value_inv, "GADGETS_IS_ZERO_inverse_witness")] + .iter() + .for_each(|(col, ann)| region.name_column(|| format!("{}_{}", prefix, ann), *col)); + } } +#[derive(Debug, Clone)] /// Wrapper arround [`IsZeroConfig`] for which [`Chip`] is implemented. pub struct IsZeroChip { config: IsZeroConfig, } - #[rustfmt::skip] impl IsZeroChip { /// Sets up the configuration of the chip by creating the required columns @@ -100,9 +105,14 @@ impl IsZeroChip { pub fn construct(config: IsZeroConfig) -> Self { IsZeroChip { config } } + + /// Annotates columns of this gadget embedded within a circuit region. + pub fn annotate_columns_in_region(&self, region: &mut Region, prefix: &str) { + self.config.annotate_columns_in_region(region, prefix) + } } -impl IsZeroInstruction for IsZeroChip { +impl IsZeroInstruction for IsZeroChip { fn assign( &self, region: &mut Region<'_, F>, @@ -110,8 +120,7 @@ impl IsZeroInstruction for IsZeroChip { value: Value, ) -> Result<(), Error> { let config = self.config(); - - let value_invert = value.map(|value| value.invert().unwrap_or(F::zero())); + let value_invert = value.map(|value| value.invert().unwrap_or(F::ZERO)); region.assign_advice( || "witness inverse of value", config.value_inv, @@ -123,7 +132,7 @@ impl IsZeroInstruction for IsZeroChip { } } -impl Chip for IsZeroChip { +impl Chip for IsZeroChip { type Config = IsZeroConfig; type Loaded = (); @@ -150,7 +159,7 @@ mod test { use std::marker::PhantomData; macro_rules! try_test_circuit { - ($values:expr, $checks:expr, $result:expr) => {{ + ($values:expr, $checks:expr) => {{ // let k = usize::BITS - $values.len().leading_zeros(); // TODO: remove zk blinding factors in halo2 to restore the @@ -162,7 +171,7 @@ mod test { _marker: PhantomData, }; let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), $result); + prover.assert_satisfied_par() }}; } @@ -179,7 +188,7 @@ mod test { _marker: PhantomData, }; let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); - assert!(prover.verify().is_err()); + assert!(prover.verify_par().is_err()); }}; } @@ -204,6 +213,7 @@ mod test { impl Circuit for TestCircuit { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() @@ -299,15 +309,10 @@ mod test { } // ok - try_test_circuit!( - vec![1, 2, 3, 4, 5], - vec![false, false, false, false], - Ok(()) - ); + try_test_circuit!(vec![1, 2, 3, 4, 5], vec![false, false, false, false]); try_test_circuit!( vec![1, 2, 2, 3, 3], // - vec![false, true, false, true], - Ok(()) + vec![false, true, false, true] ); // error try_test_circuit_error!(vec![1, 2, 3, 4, 5], vec![true, true, true, true]); @@ -336,6 +341,7 @@ mod test { impl Circuit for TestCircuit { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() @@ -433,16 +439,8 @@ mod test { } // ok - try_test_circuit!( - vec![(1, 2), (3, 4), (5, 6)], - vec![false, false, false], - Ok(()) - ); - try_test_circuit!( - vec![(1, 1), (3, 4), (6, 6)], - vec![true, false, true], - Ok(()) - ); + try_test_circuit!(vec![(1, 2), (3, 4), (5, 6)], vec![false, false, false]); + try_test_circuit!(vec![(1, 1), (3, 4), (6, 6)], vec![true, false, true]); // error try_test_circuit_error!(vec![(1, 2), (3, 4), (5, 6)], vec![true, true, true]); try_test_circuit_error!(vec![(1, 1), (3, 4), (6, 6)], vec![false, true, false]); diff --git a/gadgets/src/less_than.rs b/gadgets/src/less_than.rs index 035e036213..49285951da 100644 --- a/gadgets/src/less_than.rs +++ b/gadgets/src/less_than.rs @@ -2,9 +2,8 @@ use eth_types::Field; use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{Chip, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, + circuit::{Chip, Layouter, Region, Value}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, poly::Rotation, }; @@ -14,7 +13,7 @@ use super::{ }; /// Instruction that the Lt chip needs to implement. -pub trait LtInstruction { +pub trait LtInstruction { /// Assign the lhs and rhs witnesses to the Lt chip's region. fn assign( &self, @@ -23,6 +22,9 @@ pub trait LtInstruction { lhs: F, rhs: F, ) -> Result<(), Error>; + + /// Load the u8 lookup table. + fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error>; } /// Config for the Lt chip. @@ -31,8 +33,9 @@ pub struct LtConfig { /// Denotes the lt outcome. If lhs < rhs then lt == 1, otherwise lt == 0. pub lt: Column, /// Denotes the bytes representation of the difference between lhs and rhs. - /// Note that the range of each byte is not checked by this config. pub diff: [Column; N_BYTES], + /// Denotes the range within which each byte should lie. + pub u8: Column, /// Denotes the range within which both lhs and rhs lie. pub range: F, } @@ -61,6 +64,7 @@ impl LtChip { let lt = meta.advice_column(); let diff = [(); N_BYTES].map(|_| meta.advice_column()); let range = pow_of_two(N_BYTES * 8); + let u8 = meta.fixed_column(); meta.create_gate("lt gate", |meta| { let q_enable = q_enable(meta); @@ -81,7 +85,22 @@ impl LtChip { .map(move |poly| q_enable.clone() * poly) }); - LtConfig { lt, diff, range } + meta.annotate_lookup_any_column(u8, || "LOOKUP_u8"); + + diff[0..N_BYTES].iter().for_each(|column| { + meta.lookup_any("range check for u8", |meta| { + let u8_cell = meta.query_advice(*column, Rotation::cur()); + let u8_range = meta.query_fixed(u8, Rotation::cur()); + vec![(u8_cell, u8_range)] + }); + }); + + LtConfig { + lt, + diff, + range, + u8, + } } /// Constructs a Lt chip given a config. @@ -108,7 +127,7 @@ impl LtInstruction for LtChip { || Value::known(F::from(lt as u64)), )?; - let diff = (lhs - rhs) + (if lt { config.range } else { F::zero() }); + let diff = (lhs - rhs) + (if lt { config.range } else { F::ZERO }); let diff_bytes = diff.to_repr(); let diff_bytes = diff_bytes.as_ref(); for (idx, diff_column) in config.diff.iter().enumerate() { @@ -122,6 +141,25 @@ impl LtInstruction for LtChip { Ok(()) } + + fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + const RANGE: usize = 256; + + layouter.assign_region( + || "load u8 range check table", + |mut region| { + for i in 0..RANGE { + region.assign_fixed( + || "assign cell in fixed column", + self.config.u8, + i, + || Value::known(F::from(i as u64)), + )?; + } + Ok(()) + }, + ) + } } impl Chip for LtChip { @@ -139,10 +177,9 @@ impl Chip for LtChip { #[cfg(test)] mod test { - use super::{LtChip, LtConfig, LtInstruction}; + use super::*; use eth_types::Field; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, halo2curves::bn256::Fr as Fp, @@ -157,7 +194,7 @@ mod test { // TODO: remove zk blinding factors in halo2 to restore the // correct k (without the extra + 2). - let k = usize::BITS - $values.len().leading_zeros() + 2; + let k = 9; let circuit = TestCircuit:: { values: Some($values), checks: Some($checks), @@ -174,7 +211,7 @@ mod test { // TODO: remove zk blinding factors in halo2 to restore the // correct k (without the extra + 2). - let k = usize::BITS - $values.len().leading_zeros() + 2; + let k = 9; let circuit = TestCircuit:: { values: Some($values), checks: Some($checks), @@ -196,7 +233,7 @@ mod test { } #[derive(Default)] - struct TestCircuit { + struct TestCircuit { values: Option>, // checks[i] = lt(values[i + 1], values[i]) checks: Option>, @@ -206,6 +243,7 @@ mod test { impl Circuit for TestCircuit { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() @@ -258,6 +296,8 @@ mod test { let (first_value, values) = values.split_at(1); let first_value = first_value[0]; + chip.load(&mut layouter)?; + layouter.assign_region( || "witness", |mut region| { @@ -314,7 +354,7 @@ mod test { } #[derive(Default)] - struct TestCircuit { + struct TestCircuit { values: Option>, // checks[i] = lt(values[i].0 - values[i].1) checks: Option>, @@ -324,6 +364,7 @@ mod test { impl Circuit for TestCircuit { type Config = TestCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = (); fn without_witnesses(&self) -> Self { Self::default() @@ -380,6 +421,8 @@ mod test { .ok_or(Error::Synthesis)?; let checks = self.checks.as_ref().ok_or(Error::Synthesis)?; + chip.load(&mut layouter)?; + layouter.assign_region( || "witness", |mut region| { diff --git a/gadgets/src/lib.rs b/gadgets/src/lib.rs index 54865a927e..a7150262ee 100644 --- a/gadgets/src/lib.rs +++ b/gadgets/src/lib.rs @@ -11,32 +11,15 @@ #![deny(unsafe_code)] #![deny(clippy::debug_assert_with_mut_call)] +pub mod batched_is_zero; pub mod binary_number; -pub mod evm_word; pub mod is_zero; pub mod less_than; -pub mod monotone; +pub mod mul_add; pub mod util; use eth_types::Field; -use halo2_proofs::{ - circuit::{AssignedCell, Value}, - plonk::Expression, -}; - -#[allow(dead_code)] -/// An assigned cell in the circuit. -#[derive(Clone, Debug)] -pub struct Variable { - assig_cell: AssignedCell, - value: Value, -} - -impl Variable { - pub(crate) fn new(assig_cell: AssignedCell, value: Value) -> Self { - Self { assig_cell, value } - } -} +use halo2_proofs::plonk::Expression; /// Restrict an expression to be a boolean. pub fn bool_check(value: Expression) -> Expression { diff --git a/gadgets/src/monotone.rs b/gadgets/src/monotone.rs deleted file mode 100644 index 4110dfb250..0000000000 --- a/gadgets/src/monotone.rs +++ /dev/null @@ -1,307 +0,0 @@ -//! # Monotone mod -//! Monotone gadget helps to check if an advice column is monotonically -//! increasing within a range. With strict enabled, it disallows equality of two -//! cell. -use halo2_proofs::arithmetic::FieldExt; -use halo2_proofs::{ - circuit::{Chip, Layouter, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, - poly::Rotation, -}; -use std::{marker::PhantomData, u64}; - -#[allow(dead_code)] -#[derive(Clone, Debug)] -pub(crate) struct MonotoneConfig { - range_table: Column, - value: Column, -} - -/// MonotoneChip helps to check if an advice column is monotonically increasing -/// within a range. With strict enabled, it disallows equality of two cell. -pub(crate) struct MonotoneChip { - config: MonotoneConfig, - _marker: PhantomData, -} - -#[allow(dead_code)] -impl - MonotoneChip -{ - /// configure which column should be check. q_enable here as a fn is - /// flexible for synthetic selector instead of a fixed one. - pub fn configure( - meta: &mut ConstraintSystem, - q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression, - value: Column, - ) -> MonotoneConfig { - let range_table = meta.fixed_column(); - - let config = MonotoneConfig { range_table, value }; - - meta.lookup_any("Range check", |meta| { - let q_enable = q_enable(meta); - let range_table = meta.query_fixed(config.range_table, Rotation::cur()); - let value_diff = { - let value_cur = meta.query_advice(value, Rotation::cur()); - let value_prev = meta.query_advice(value, Rotation::prev()); - if INCR { - value_cur - value_prev - } else { - value_prev - value_cur - } - }; - - // If strict monotone, we subtract diff by one - // to make sure zero lookup fail - let min_diff = Expression::Constant(F::from(STRICT as u64)); - - vec![(q_enable * (value_diff - min_diff), range_table)] - }); - - config - } - - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "range_table", - |mut meta| { - let max = RANGE - STRICT as usize; - - for idx in 0..=max { - meta.assign_fixed( - || "range_table_value", - self.config.range_table, - idx, - || Value::known(F::from(idx as u64)), - )?; - } - - Ok(()) - }, - ) - } - - pub fn construct(config: MonotoneConfig) -> Self { - Self { - config, - _marker: PhantomData, - } - } -} - -impl Chip - for MonotoneChip -{ - type Config = MonotoneConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -#[cfg(test)] -mod test { - use super::{MonotoneChip, MonotoneConfig, Value}; - use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{Layouter, SimpleFloorPlanner}, - dev::{ - FailureLocation, MockProver, - VerifyFailure::{self, Lookup}, - }, - halo2curves::bn256::Fr as Fp, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Selector}, - }; - use std::marker::PhantomData; - - #[derive(Clone, Debug)] - struct TestCircuitConfig { - q_enable: Selector, - value: Column, - mono_incr: MonotoneConfig, - } - - #[derive(Default)] - struct TestCircuit { - values: Option>, - _marker: PhantomData, - } - - impl Circuit - for TestCircuit - { - type Config = TestCircuitConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let q_enable = meta.complex_selector(); - let value = meta.advice_column(); - - let mono_incr = MonotoneChip::::configure( - meta, - |meta| meta.query_selector(q_enable), - value, - ); - - Self::Config { - q_enable, - value, - mono_incr, - } - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let monotone_chip = - MonotoneChip::::construct(config.mono_incr.clone()); - - monotone_chip.load(&mut layouter)?; - - let values: Vec<_> = self - .values - .as_ref() - .map(|values| values.iter().map(|value| F::from(*value)).collect()) - .ok_or(Error::Synthesis)?; - - layouter.assign_region( - || "witness", - |mut region| { - for (idx, value) in values.iter().enumerate() { - region.assign_advice( - || "value", - config.value, - idx, - || Value::known(*value), - )?; - if idx > 0 { - config.q_enable.enable(&mut region, idx)?; - } - } - - Ok(()) - }, - ) - } - } - - macro_rules! gen_try_test_circuit { - ($range:expr, $incr:expr, $strict:expr) => { - fn try_test_circuit(values: Vec, result: Result<(), Vec>) { - let circuit = TestCircuit:: { - values: Some(values), - _marker: PhantomData, - }; - let prover = MockProver::::run( - usize::BITS - ($range as usize).leading_zeros(), - &circuit, - vec![], - ) - .unwrap(); - assert_eq!(prover.verify(), result); - } - }; - } - - #[test] - fn strict_monotonically_increasing() { - gen_try_test_circuit!(100, true, true); - - // strict monotone in range (ok) - try_test_circuit(vec![1, 2, 3, 4, 104], Ok(())); - try_test_circuit(vec![1001, 1002, 1003, 1004, 1104], Ok(())); - // non-strict monotone in range (error) - try_test_circuit( - vec![1, 2, 2, 4, 4], - Err(vec![ - Lookup { - name: "Range check", - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 2, - }, - }, - Lookup { - name: "Range check", - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 4, - }, - }, - ]), - ); - // out of range (error) - try_test_circuit( - vec![1, 2, 3, 4, 105], - Err(vec![Lookup { - name: "Range check", - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 4, - }, - }]), - ); - // not monotone (error) - try_test_circuit( - vec![1, 2, 3, 103, 4], - Err(vec![Lookup { - name: "Range check", - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 4, - }, - }]), - ); - } - - #[test] - fn non_strict_monotonically_increasing() { - gen_try_test_circuit!(100, true, false); - - // strict monotone in range (ok) - try_test_circuit(vec![1, 2, 3, 4, 104], Ok(())); - try_test_circuit(vec![1001, 1002, 1003, 1004, 1104], Ok(())); - // non-strict monotone in range (ok) - try_test_circuit(vec![1, 2, 2, 4, 4], Ok(())); - // out of range (error) - try_test_circuit( - vec![1, 2, 3, 4, 105], - Err(vec![Lookup { - name: "Range check", - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 4, - }, - }]), - ); - // not monotone (error) - try_test_circuit( - vec![1, 2, 3, 103, 4], - Err(vec![Lookup { - name: "Range check", - lookup_index: 0, - location: FailureLocation::InRegion { - region: halo2_proofs::dev::metadata::Region::from((1, "witness")), - offset: 4, - }, - }]), - ); - } -} diff --git a/gadgets/src/mul_add.rs b/gadgets/src/mul_add.rs new file mode 100644 index 0000000000..3710f7b9c6 --- /dev/null +++ b/gadgets/src/mul_add.rs @@ -0,0 +1,504 @@ +//! Chip that implements instructions to check: a * b + c == d (mod 2^256) where +//! a, b, c and d are all 256-bit words. +//! +//! The circuit layout is as follows: +#[rustfmt::skip] +// | q_step | col0 | col1 | col2 | col3 | col4 | +// |--------|-----------|-----------|-----------|-----------|-----------| +// | 1 | a_limb0 | a_limb1 | a_limb2 | a_limb3 | - | +// | 0 | b_limb0 | b_limb1 | b_limb2 | b_limb3 | - | +// | 0 | c_lo | c_hi | d_lo | d_hi | - | +// | 0 | carry_lo0 | carry_lo1 | carry_lo2 | carry_lo3 | carry_lo4 | +// | 0 | carry_lo5 | carry_lo6 | carry_lo7 | carry_lo8 | - | +// | 0 | carry_hi0 | carry_hi1 | carry_hi2 | carry_hi3 | carry_hi4 | +// | 0 | carry_hi5 | carry_hi6 | carry_hi7 | carry_hi8 | - | +// |--------|-----------|-----------|-----------|-----------|-----------| + +use eth_types::{Field, ToLittleEndian, Word}; +use halo2_proofs::{ + circuit::{Region, Value}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, + poly::Rotation, +}; + +use crate::util::{expr_from_bytes, pow_of_two, split_u256, split_u256_limb64, Expr}; + +/// Config for the MulAddChip. +#[derive(Clone, Debug)] +pub struct MulAddConfig { + /// First of the columns which we use over multiple rows to represent the + /// schema described above. + pub col0: Column, + /// Second of the columns which we use over multiple rows to represent the + /// schema described above. + pub col1: Column, + /// Third of the columns which we use over multiple rows to represent the + /// schema described above. + pub col2: Column, + /// Fourth of the columns which we use over multiple rows to represent the + /// schema described above. + pub col3: Column, + /// Fifth of the columns which we use over multiple rows to represent the + /// schema described above. + pub col4: Column, + /// Sum of the parts higher than 256-bit in the product. + pub overflow: Expression, +} + +impl MulAddConfig { + /// 64-bit limbs representing `a` from the equation `a * b + c == d`. + pub fn a_limbs_cur( + &self, + meta: &mut VirtualCells<'_, F>, + ) -> (Expression, Expression, Expression, Expression) { + ( + meta.query_advice(self.col0, Rotation::cur()), + meta.query_advice(self.col1, Rotation::cur()), + meta.query_advice(self.col2, Rotation::cur()), + meta.query_advice(self.col3, Rotation::cur()), + ) + } + + /// 64-bit limbs representing `b` from the equation `a * b + c == d`. + pub fn b_limbs_cur( + &self, + meta: &mut VirtualCells<'_, F>, + ) -> (Expression, Expression, Expression, Expression) { + ( + meta.query_advice(self.col0, Rotation(1)), + meta.query_advice(self.col1, Rotation(1)), + meta.query_advice(self.col2, Rotation(1)), + meta.query_advice(self.col3, Rotation(1)), + ) + } + + /// 128-bit lo-hi parts of `c` from the equation `a * b + c == d`. + pub fn c_lo_hi_cur(&self, meta: &mut VirtualCells<'_, F>) -> (Expression, Expression) { + ( + meta.query_advice(self.col0, Rotation(2)), + meta.query_advice(self.col1, Rotation(2)), + ) + } + + /// 128-bit lo-hi parts of `d` from the equation `a * b + c == d`. + pub fn d_lo_hi_cur(&self, meta: &mut VirtualCells<'_, F>) -> (Expression, Expression) { + ( + meta.query_advice(self.col2, Rotation(2)), + meta.query_advice(self.col3, Rotation(2)), + ) + } + + /// 128-bit lo-hi parts of `d` from the next step. + pub fn d_lo_hi_next(&self, meta: &mut VirtualCells<'_, F>) -> (Expression, Expression) { + ( + meta.query_advice(self.col2, Rotation(9)), + meta.query_advice(self.col3, Rotation(9)), + ) + } +} + +/// Chip to constrain a * b + c == d (mod 2^256). +#[derive(Clone, Debug)] +pub struct MulAddChip { + /// Config for the chip. + pub config: MulAddConfig, +} + +impl MulAddChip { + /// Configure the MulAdd chip. + #[allow(clippy::too_many_arguments)] + pub fn configure( + meta: &mut ConstraintSystem, + q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression, + ) -> MulAddConfig { + let col0 = meta.advice_column(); + let col1 = meta.advice_column(); + let col2 = meta.advice_column(); + let col3 = meta.advice_column(); + let col4 = meta.advice_column(); + let mut overflow = 0.expr(); + + meta.create_gate("mul add gate", |meta| { + let q_enable = q_enable(meta); + + let a_limbs = + [col0, col1, col2, col3].map(|column| meta.query_advice(column, Rotation::cur())); + let b_limbs = + [col0, col1, col2, col3].map(|column| meta.query_advice(column, Rotation::next())); + + let c_lo = meta.query_advice(col0, Rotation(2)); + let c_hi = meta.query_advice(col1, Rotation(2)); + let d_lo = meta.query_advice(col2, Rotation(2)); + let d_hi = meta.query_advice(col3, Rotation(2)); + + let carry_los = [col0, col1, col2, col3, col4] + .map(|col| meta.query_advice(col, Rotation(3))) + .into_iter() + .chain([col0, col1, col2, col3].map(|col| meta.query_advice(col, Rotation(4)))) + .collect::>>(); + let carry_his = [col0, col1, col2, col3, col4] + .map(|col| meta.query_advice(col, Rotation(5))) + .into_iter() + .chain([col0, col1, col2, col3].map(|col| meta.query_advice(col, Rotation(6)))) + .collect::>>(); + + let carry_lo_expr = expr_from_bytes(&carry_los); + let carry_hi_expr = expr_from_bytes(&carry_his); + + let t0 = a_limbs[0].clone() * b_limbs[0].clone(); + let t1 = + a_limbs[0].clone() * b_limbs[1].clone() + a_limbs[1].clone() * b_limbs[0].clone(); + let t2 = a_limbs[0].clone() * b_limbs[2].clone() + + a_limbs[1].clone() * b_limbs[1].clone() + + a_limbs[2].clone() * b_limbs[0].clone(); + let t3 = a_limbs[0].clone() * b_limbs[3].clone() + + a_limbs[1].clone() * b_limbs[2].clone() + + a_limbs[2].clone() * b_limbs[1].clone() + + a_limbs[3].clone() * b_limbs[0].clone(); + overflow = carry_hi_expr.clone() + + a_limbs[1].clone() * b_limbs[3].clone() + + a_limbs[2].clone() * b_limbs[2].clone() + + a_limbs[2].clone() * b_limbs[3].clone() + + a_limbs[3].clone() * b_limbs[1].clone() + + a_limbs[3].clone() * b_limbs[2].clone() + + a_limbs[3].clone() * b_limbs[3].clone(); + + let check_a = t0.expr() + t1.expr() * pow_of_two::(64) + c_lo + - (d_lo + carry_lo_expr.clone() * pow_of_two::(128)); + let check_b = t2.expr() + t3.expr() * pow_of_two::(64) + c_hi + carry_lo_expr + - (d_hi + carry_hi_expr * pow_of_two::(128)); + + [check_a, check_b] + .into_iter() + .map(move |poly| q_enable.clone() * poly) + }); + + MulAddConfig { + col0, + col1, + col2, + col3, + col4, + overflow, + } + } + + /// Construct the MulAdd chip given a configuration. + pub fn construct(config: MulAddConfig) -> Self { + Self { config } + } + + /// Assign witness data to the MulAdd chip. + pub fn assign( + &self, + region: &mut Region<'_, F>, + offset: usize, + words: [Word; 4], + ) -> Result<(), Error> { + let (a, b, c, d) = (words[0], words[1], words[2], words[3]); + + let a_limbs = split_u256_limb64(&a); + let b_limbs = split_u256_limb64(&b); + let (c_lo, c_hi) = split_u256(&c); + let (d_lo, d_hi) = split_u256(&d); + + let t0 = a_limbs[0] * b_limbs[0]; + let t1 = a_limbs[0] * b_limbs[1] + a_limbs[1] * b_limbs[0]; + let t2 = a_limbs[0] * b_limbs[2] + a_limbs[1] * b_limbs[1] + a_limbs[2] * b_limbs[0]; + let t3 = a_limbs[0] * b_limbs[3] + + a_limbs[1] * b_limbs[2] + + a_limbs[2] * b_limbs[1] + + a_limbs[3] * b_limbs[0]; + + let (c_lo_minus_d_lo, _) = c_lo.overflowing_sub(d_lo); + let temp = t0 + (t1 << 64); + let (carry_lo, _) = temp.overflowing_add(c_lo_minus_d_lo); + let carry_lo = carry_lo >> 128; + let (carry_lo_minus_d_hi, _) = carry_lo.overflowing_sub(d_hi); + let temp = t2 + (t3 << 64) + c_hi; + let (carry_hi, _) = temp.overflowing_add(carry_lo_minus_d_hi); + let carry_hi = carry_hi >> 128; + + // a limbs. + for (i, (column, value)) in [ + self.config.col0, + self.config.col1, + self.config.col2, + self.config.col3, + ] + .into_iter() + .zip(a_limbs) + .enumerate() + { + region.assign_advice( + || format!("a limb ({})", i), + column, + offset, + || Value::known(F::from(value.as_u64())), + )?; + } + region.assign_advice( + || format!("unused col: {}", offset), + self.config.col4, + offset, + || Value::known(F::ZERO), + )?; + + // b limbs. + for (i, (column, value)) in [ + self.config.col0, + self.config.col1, + self.config.col2, + self.config.col3, + ] + .into_iter() + .zip(b_limbs) + .enumerate() + { + region.assign_advice( + || format!("b limb ({})", i), + column, + offset + 1, + || Value::known(F::from(value.as_u64())), + )?; + } + region.assign_advice( + || format!("unused col {}", offset + 1), + self.config.col4, + offset + 1, + || Value::known(F::ZERO), + )?; + + // c_lo, c_hi, d_lo, d_hi. + region.assign_advice( + || "c_lo", + self.config.col0, + offset + 2, + || Value::known(F::from_u128(c_lo.as_u128())), + )?; + region.assign_advice( + || "c_hi", + self.config.col1, + offset + 2, + || Value::known(F::from_u128(c_hi.as_u128())), + )?; + region.assign_advice( + || "d_lo", + self.config.col2, + offset + 2, + || Value::known(F::from_u128(d_lo.as_u128())), + )?; + region.assign_advice( + || "d_hi", + self.config.col3, + offset + 2, + || Value::known(F::from_u128(d_hi.as_u128())), + )?; + region.assign_advice( + || format!("unused col: {}", offset + 2), + self.config.col4, + offset + 2, + || Value::known(F::ZERO), + )?; + + // carry_lo. + for (i, ((col, rot), val)) in [ + (self.config.col0, offset + 3), + (self.config.col1, offset + 3), + (self.config.col2, offset + 3), + (self.config.col3, offset + 3), + (self.config.col4, offset + 3), + (self.config.col0, offset + 4), + (self.config.col1, offset + 4), + (self.config.col2, offset + 4), + (self.config.col3, offset + 4), + ] + .into_iter() + .zip(carry_lo.to_le_bytes().iter()) + .enumerate() + { + region.assign_advice( + || format!("carry lo ({})", i), + col, + rot, + || Value::known(F::from(*val as u64)), + )?; + } + region.assign_advice( + || format!("unused col: {}", offset + 4), + self.config.col4, + offset + 4, + || Value::known(F::ZERO), + )?; + + // carry_hi. + for (i, ((col, rot), val)) in [ + (self.config.col0, offset + 5), + (self.config.col1, offset + 5), + (self.config.col2, offset + 5), + (self.config.col3, offset + 5), + (self.config.col4, offset + 5), + (self.config.col0, offset + 6), + (self.config.col1, offset + 6), + (self.config.col2, offset + 6), + (self.config.col3, offset + 6), + ] + .into_iter() + .zip(carry_hi.to_le_bytes().iter()) + .enumerate() + { + region.assign_advice( + || format!("carry hi ({})", i), + col, + rot, + || Value::known(F::from(*val as u64)), + )?; + } + region.assign_advice( + || format!("unused col: {}", offset + 6), + self.config.col4, + offset + 6, + || Value::known(F::ZERO), + )?; + + Ok(()) + } + + /// Annotates columns of this gadget embedded within a circuit region. + pub fn annotate_columns_in_region(&self, region: &mut Region, prefix: &str) { + [ + (self.config.col0, "GADGET_MUL_ADD_col0"), + (self.config.col1, "GADGET_MUL_ADD_col1"), + (self.config.col2, "GADGET_MUL_ADD_col2"), + (self.config.col3, "GADGET_MUL_ADD_col3"), + (self.config.col4, "GADGET_MUL_ADD_col4"), + ] + .iter() + .for_each(|(col, ann)| region.name_column(|| format!("{}_{}", prefix, ann), *col)); + } +} + +#[cfg(test)] +mod test { + use std::marker::PhantomData; + + use eth_types::{Field, Word}; + use halo2_proofs::{ + circuit::SimpleFloorPlanner, + dev::MockProver, + halo2curves::bn256::Fr as Fp, + plonk::{Circuit, Selector}, + }; + use rand::Rng; + + use crate::mul_add::{MulAddChip, MulAddConfig}; + + macro_rules! try_test_circuit { + ($values:expr) => {{ + let k = 10; + let circuit = TestCircuit:: { + values: $values, + _marker: PhantomData, + }; + let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); + prover.assert_satisfied_par() + }}; + } + + macro_rules! try_test_circuit_error { + ($values:expr) => {{ + let k = 10; + let circuit = TestCircuit:: { + values: $values, + _marker: PhantomData, + }; + let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); + assert!(prover.verify().is_err()); + }}; + } + + pub(crate) fn rand_bytes_array() -> [u8; N] { + [(); N].map(|_| rand::random()) + } + + pub(crate) fn rand_word() -> Word { + Word::from_big_endian(&rand_bytes_array::<32>()) + } + + #[test] + fn mul_over_rows() { + #[derive(Clone)] + struct TestCircuitConfig { + q_enable: Selector, + mul_config: MulAddConfig, + } + + #[derive(Clone, Default)] + struct TestCircuit { + /// (a, b, d) tuples for a * b == d (mod 2^256). + values: Vec<(Word, Word, Word)>, + _marker: PhantomData, + } + + impl Circuit for TestCircuit { + type Config = TestCircuitConfig; + type FloorPlanner = SimpleFloorPlanner; + type Params = (); + + fn configure(meta: &mut halo2_proofs::plonk::ConstraintSystem) -> Self::Config { + let q_enable = meta.complex_selector(); + let mul_config = MulAddChip::configure(meta, |meta| meta.query_selector(q_enable)); + Self::Config { + q_enable, + mul_config, + } + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl halo2_proofs::circuit::Layouter, + ) -> Result<(), halo2_proofs::plonk::Error> { + let chip = MulAddChip::construct(config.mul_config); + layouter.assign_region( + || "witness", + |mut region| { + let mut offset = 0; + for (a, b, d) in self.values.iter() { + config.q_enable.enable(&mut region, offset)?; + chip.assign(&mut region, offset, [*a, *b, Word::zero(), *d])?; + offset += 7 + } + Ok(()) + }, + ) + } + + fn without_witnesses(&self) -> Self { + Self::default() + } + } + + let mut rng = rand::thread_rng(); + let n = 100; + let mut values = Vec::with_capacity(n); + for _ in 0..n { + let a = rand_word(); + let b = rand_word(); + let (d, _) = a.overflowing_mul(b); + values.push((a, b, d)); + } + + try_test_circuit!(values.clone()); + try_test_circuit_error!(values + .into_iter() + .map(|(a, b, d)| { + if rng.gen::() { + (a, b, d + 1) + } else { + (a, b, d - 1) + } + }) + .collect::>()); + } +} diff --git a/gadgets/src/util.rs b/gadgets/src/util.rs index 373c03ffd5..978777a533 100644 --- a/gadgets/src/util.rs +++ b/gadgets/src/util.rs @@ -1,7 +1,7 @@ //! Utility traits, functions used in the crate. use eth_types::{ evm_types::{GasCost, OpcodeId}, - Field, + Field, U256, }; use halo2_proofs::plonk::Expression; @@ -9,7 +9,7 @@ use halo2_proofs::plonk::Expression; pub mod sum { use crate::util::Expr; use eth_types::Field; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use halo2_proofs::plonk::Expression; /// Returns an expression for the sum of the list of expressions. pub fn expr, I: IntoIterator>(inputs: I) -> Expression { @@ -19,10 +19,10 @@ pub mod sum { } /// Returns the sum of the given list of values within the field. - pub fn value(values: &[u8]) -> F { + pub fn value(values: &[u8]) -> F { values .iter() - .fold(F::zero(), |acc, value| acc + F::from(*value as u64)) + .fold(F::ZERO, |acc, value| acc + F::from(*value as u64)) } } @@ -31,7 +31,7 @@ pub mod sum { pub mod and { use crate::util::Expr; use eth_types::Field; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use halo2_proofs::plonk::Expression; /// Returns an expression that evaluates to 1 only if all the expressions in /// the given list are 1, else returns 0. @@ -42,8 +42,8 @@ pub mod and { } /// Returns the product of all given values. - pub fn value(inputs: Vec) -> F { - inputs.iter().fold(F::one(), |acc, input| acc * input) + pub fn value(inputs: Vec) -> F { + inputs.iter().fold(F::ONE, |acc, input| acc * input) } } @@ -53,7 +53,7 @@ pub mod or { use super::{and, not}; use crate::util::Expr; use eth_types::Field; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use halo2_proofs::plonk::Expression; /// Returns an expression that evaluates to 1 if any expression in the given /// list is 1. Returns 0 if all the expressions were 0. @@ -62,7 +62,7 @@ pub mod or { } /// Returns the value after passing all given values through the OR gate. - pub fn value(inputs: Vec) -> F { + pub fn value(inputs: Vec) -> F { not::value(and::value(inputs.into_iter().map(not::value).collect())) } } @@ -72,7 +72,7 @@ pub mod or { pub mod not { use crate::util::Expr; use eth_types::Field; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use halo2_proofs::plonk::Expression; /// Returns an expression that represents the NOT of the given expression. pub fn expr>(b: E) -> Expression { @@ -80,8 +80,8 @@ pub mod not { } /// Returns a value that represents the NOT of the given value. - pub fn value(b: F) -> F { - F::one() - b + pub fn value(b: F) -> F { + F::ONE - b } } @@ -90,7 +90,7 @@ pub mod not { pub mod xor { use crate::util::Expr; use eth_types::Field; - use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; + use halo2_proofs::plonk::Expression; /// Returns an expression that represents the XOR of the given expression. pub fn expr>(a: E, b: E) -> Expression { @@ -98,7 +98,7 @@ pub mod xor { } /// Returns a value that represents the XOR of the given value. - pub fn value(a: F, b: F) -> F { + pub fn value(a: F, b: F) -> F { a + b - F::from(2u64) * a * b } } @@ -123,7 +123,7 @@ pub mod select { /// Returns the `when_true` value when the selector is true, else returns /// the `when_false` value. pub fn value(selector: F, when_true: F, when_false: F) -> F { - selector * when_true + (F::one() - selector) * when_false + selector * when_true + (F::ONE - selector) * when_false } /// Returns the `when_true` word when selector is true, else returns the @@ -133,7 +133,7 @@ pub mod select { when_true: [u8; 32], when_false: [u8; 32], ) -> [u8; 32] { - if selector == F::one() { + if selector == F::ONE { when_true } else { when_false @@ -141,6 +141,35 @@ pub mod select { } } +/// Returns the power of number using straigtforward multiplications +pub mod pow { + use crate::util::Expr; + use eth_types::Field; + use halo2_proofs::plonk::Expression; + + use super::Scalar; + + /// Returns the `when_true` expression when the selector is true, else + /// returns the `when_false` expression. + pub fn expr(value: Expression, exponent: usize) -> Expression { + let mut result = 1.expr(); + for _ in 0..exponent { + result = result * value.expr(); + } + result + } + + /// Returns the `when_true` value when the selector is true, else returns + /// the `when_false` value. + pub fn value(value: F, exponent: usize) -> F { + let mut result = 1.scalar(); + for _ in 0..exponent { + result *= value; + } + result + } +} + /// Trait that implements functionality to get a scalar from /// commonly used types. pub trait Scalar { @@ -210,19 +239,14 @@ impl_expr!(GasCost, GasCost::as_u64); impl Scalar for i32 { #[inline] fn scalar(&self) -> F { - F::from(self.unsigned_abs() as u64) - * if self.is_negative() { - -F::one() - } else { - F::one() - } + F::from(self.unsigned_abs() as u64) * if self.is_negative() { -F::ONE } else { F::ONE } } } impl Scalar for &F { #[inline] fn scalar(&self) -> F { - *self.clone() + *(*self) } } @@ -251,7 +275,7 @@ impl Expr for &Expression { /// single expression. pub fn expr_from_bytes>(bytes: &[E]) -> Expression { let mut value = 0.expr(); - let mut multiplier = F::one(); + let mut multiplier = F::ONE; for byte in bytes.iter() { value = value + byte.expr() * multiplier; multiplier *= F::from(256); @@ -259,7 +283,25 @@ pub fn expr_from_bytes>(bytes: &[E]) -> Expression { value } -/// Returns 2**by as FieldExt +/// Returns 2**by as Field pub fn pow_of_two(by: usize) -> F { - F::from(2).pow(&[by as u64, 0, 0, 0]) + F::from(2).pow([by as u64, 0, 0, 0]) +} + +/// Returns tuple consists of low and high part of U256 +pub fn split_u256(value: &U256) -> (U256, U256) { + ( + U256([value.0[0], value.0[1], 0, 0]), + U256([value.0[2], value.0[3], 0, 0]), + ) +} + +/// Split a U256 value into 4 64-bit limbs stored in U256 values. +pub fn split_u256_limb64(value: &U256) -> [U256; 4] { + [ + U256([value.0[0], 0, 0, 0]), + U256([value.0[1], 0, 0, 0]), + U256([value.0[2], 0, 0, 0]), + U256([value.0[3], 0, 0, 0]), + ] } diff --git a/geth-utils/Cargo.toml b/geth-utils/Cargo.toml index 2a0e737aab..ae6750c671 100644 --- a/geth-utils/Cargo.toml +++ b/geth-utils/Cargo.toml @@ -6,3 +6,5 @@ license = "MIT OR Apache-2.0" [build-dependencies] gobuild = "0.1.0-alpha.1" +log = "0.4.14" +env_logger = "0.9" \ No newline at end of file diff --git a/geth-utils/README.md b/geth-utils/README.md index ed7d0ea58b..91e2040dba 100644 --- a/geth-utils/README.md +++ b/geth-utils/README.md @@ -15,7 +15,7 @@ For [`./example/mstore_mload.go`](./example/mstore_mload.go) as an example, it d go run ./example/mstore_mload.go > ./mstore_mload.json ``` -### Debuging +### Debugging The execution traces returned by geth omit some information like execution errors in some situations. Moreover you may want to inspect some intermediate diff --git a/geth-utils/build.rs b/geth-utils/build.rs index f7f901315a..7bf64f596a 100644 --- a/geth-utils/build.rs +++ b/geth-utils/build.rs @@ -1,5 +1,7 @@ -use std::env; -use std::io::{self, Write}; +use std::{ + env, + io::{self, Write}, +}; fn main() { let lib_name = "go-geth-utils"; diff --git a/geth-utils/gethutil/trace.go b/geth-utils/gethutil/trace.go index 56cf94dbbf..744ce01d40 100644 --- a/geth-utils/gethutil/trace.go +++ b/geth-utils/gethutil/trace.go @@ -124,6 +124,8 @@ type TraceConfig struct { LoggerConfig *logger.Config `json:"logger_config"` } +func newUint64(val uint64) *uint64 { return &val } + func Trace(config TraceConfig) ([]*ExecutionResult, error) { chainConfig := params.ChainConfig{ ChainID: toBigInt(config.ChainID), @@ -145,7 +147,7 @@ func Trace(config TraceConfig) ([]*ExecutionResult, error) { var txsGasLimit uint64 blockGasLimit := toBigInt(config.Block.GasLimit).Uint64() - messages := make([]types.Message, len(config.Transactions)) + messages := make([]core.Message, len(config.Transactions)) for i, tx := range config.Transactions { // If gas price is specified directly, the tx is treated as legacy type. if tx.GasPrice != nil { @@ -158,19 +160,19 @@ func Trace(config TraceConfig) ([]*ExecutionResult, error) { txAccessList[i].Address = accessList.Address txAccessList[i].StorageKeys = accessList.StorageKeys } - messages[i] = types.NewMessage( - tx.From, - tx.To, - uint64(tx.Nonce), - toBigInt(tx.Value), - uint64(tx.GasLimit), - toBigInt(tx.GasPrice), - toBigInt(tx.GasFeeCap), - toBigInt(tx.GasTipCap), - tx.CallData, - txAccessList, - false, - ) + messages[i] = core.Message{ + From: tx.From, + To: tx.To, + Nonce: uint64(tx.Nonce), + Value: toBigInt(tx.Value), + GasLimit: uint64(tx.GasLimit), + GasPrice: toBigInt(tx.GasPrice), + GasFeeCap: toBigInt(tx.GasFeeCap), + GasTipCap: toBigInt(tx.GasTipCap), + Data: tx.CallData, + AccessList: txAccessList, + SkipAccountChecks: false, + } txsGasLimit += uint64(tx.GasLimit) } @@ -191,7 +193,7 @@ func Trace(config TraceConfig) ([]*ExecutionResult, error) { }, Coinbase: config.Block.Coinbase, BlockNumber: toBigInt(config.Block.Number), - Time: toBigInt(config.Block.Timestamp), + Time: toBigInt(config.Block.Timestamp).Uint64(), Difficulty: toBigInt(config.Block.Difficulty), BaseFee: toBigInt(config.Block.BaseFee), GasLimit: blockGasLimit, @@ -215,9 +217,9 @@ func Trace(config TraceConfig) ([]*ExecutionResult, error) { executionResults := make([]*ExecutionResult, len(config.Transactions)) for i, message := range messages { tracer := logger.NewStructLogger(config.LoggerConfig) - evm := vm.NewEVM(blockCtx, core.NewEVMTxContext(message), stateDB, &chainConfig, vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) + evm := vm.NewEVM(blockCtx, core.NewEVMTxContext(&message), stateDB, &chainConfig, vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true}) - result, err := core.ApplyMessage(evm, message, new(core.GasPool).AddGas(message.Gas())) + result, err := core.ApplyMessage(evm, &message, new(core.GasPool).AddGas(message.GasLimit)) if err != nil { return nil, fmt.Errorf("Failed to apply config.Transactions[%d]: %w", i, err) } diff --git a/geth-utils/go.mod b/geth-utils/go.mod index d1c9cd7465..2892aa855f 100644 --- a/geth-utils/go.mod +++ b/geth-utils/go.mod @@ -3,7 +3,7 @@ module main go 1.16 require ( - github.com/ethereum/go-ethereum v1.10.18 + github.com/ethereum/go-ethereum v1.11.5 github.com/holiman/uint256 v1.2.0 ) diff --git a/geth-utils/go.sum b/geth-utils/go.sum index 31cc98766a..62c668a662 100644 --- a/geth-utils/go.sum +++ b/geth-utils/go.sum @@ -8,34 +8,84 @@ cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTj cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= +github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= +github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= +github.com/CloudyKit/jet/v6 v6.1.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= +github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= +github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo= @@ -45,8 +95,15 @@ github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7 github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= @@ -58,16 +115,54 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= +github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= +github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= +github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= +github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= +github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= +github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= +github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= +github.com/consensys/gnark-crypto v0.9.1-0.20230105202408-1a7a29904a7c/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= @@ -76,85 +171,176 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= +github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= +github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/docker v1.6.2/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/go-ethereum v1.10.18 h1:hLEd5M+UD0GJWPaROiYMRgZXl6bi5YwoTJSthsx5CZw= -github.com/ethereum/go-ethereum v1.10.18/go.mod h1:RD3NhcSBjZpj3k+SnQq24wBrmnmie78P5R/P62iNBD8= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= +github.com/ethereum/go-ethereum v1.11.5 h1:3M1uan+LAUvdn+7wCEFrcMM4LJTeuxDrPTg/f31a5QQ= +github.com/ethereum/go-ethereum v1.11.5/go.mod h1:it7x0DWnTDMfVFdXcU6Ti4KEFQynLHVRarcSlPr0HBo= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= +github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732/go.mod h1:o/XfIXWi4/GqbQirfRm5uTbXMG5NpqxkxblnbZ+QM9I= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= +github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= +github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= @@ -163,26 +349,80 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM= @@ -190,7 +430,11 @@ github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= +github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= @@ -203,167 +447,450 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= +github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= +github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/httpexpect/v2 v2.3.1/go.mod h1:ICTf89VBKSD3KB0fsyyHviKF8G8hyepP0dOXJPWz3T0= +github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= +github.com/iris-contrib/jade v1.1.4/go.mod h1:EDqR+ur9piDl6DUgs6qRrlfzmlx/D5UybogqrXvJTBE= +github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= +github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= +github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kataras/blocks v0.0.6/go.mod h1:UK+Iwk0Oxpc0GdoJja7sEildotAUKK1LYeYcVF0COWc= +github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I= +github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= +github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= +github.com/kataras/golog v0.1.7/go.mod h1:jOSQ+C5fUqsNSwurB/oAHq1IFSb0KI3l6GMa7xB6dZA= +github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= +github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= +github.com/kataras/iris/v12 v12.2.0-beta5/go.mod h1:q26aoWJ0Knx/00iPKg5iizDK7oQQSPjbD8np0XDh6dc= +github.com/kataras/jwt v0.1.8/go.mod h1:Q5j2IkcIHnfwy+oNY3TVWuEBJNw0ADgCcXK9CaZwV4o= +github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= +github.com/kataras/neffos v0.0.20/go.mod h1:srdvC/Uo8mgrApWW0AYtiiLgMbyNPf69qPsd2FhE6MQ= +github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= +github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= +github.com/kataras/pio v0.0.10/go.mod h1:gS3ui9xSD+lAUpbYnjOGiQyY7sUMJO+EHpiRzhtZ5no= +github.com/kataras/pio v0.0.11/go.mod h1:38hH6SWH6m4DKSYmRhlrCJ5WItwWgCVrTNU62XZyUvI= +github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= +github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4= +github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= +github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= +github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= +github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailgun/raymond/v2 v2.0.46/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= +github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= +github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= +github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= +github.com/mediocregopher/radix/v3 v3.8.0/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= +github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= +github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= +github.com/nats-io/jwt/v2 v2.3.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= +github.com/nats-io/nats-server/v2 v2.8.4/go.mod h1:8zZa+Al3WsESfmgSs98Fi06dRWLH5Bnq90m5bKD/eT4= +github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nats.go v1.15.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nats.go v1.16.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI= +github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI= +github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tdewolff/minify/v2 v2.12.1/go.mod h1:p5pwbvNs1ghbFED/ZW1towGsnnWwzvM8iz8l0eURi9g= +github.com/tdewolff/minify/v2 v2.12.4/go.mod h1:h+SRvSIX3kwgwTFOpSckvSxgax3uy8kZTSF1Ojrr3bk= +github.com/tdewolff/parse/v2 v2.6.3/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= +github.com/tdewolff/parse/v2 v2.6.4/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= +github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= -github.com/tklauser/numcpus v0.2.2 h1:oyhllyrScuYI6g+h/zUvNXNp1wy7x8qQy3t/piefldA= +github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= +github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM= +github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= +github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= +github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -374,7 +901,13 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= +golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg= +golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -386,96 +919,229 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -483,21 +1149,31 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -508,24 +1184,58 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191126055441-b0650ceb63d9/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= @@ -536,11 +1246,29 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -555,44 +1283,121 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= diff --git a/geth-utils/src/lib.rs b/geth-utils/src/lib.rs index 1bdf0ee6e7..60a237164f 100644 --- a/geth-utils/src/lib.rs +++ b/geth-utils/src/lib.rs @@ -1,8 +1,10 @@ //! Connection to external EVM tracer. use core::fmt::{Display, Formatter, Result as FmtResult}; -use std::ffi::{CStr, CString}; -use std::os::raw::c_char; +use std::{ + ffi::{CStr, CString}, + os::raw::c_char, +}; extern "C" { fn CreateTrace(str: *const c_char) -> *const c_char; diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index c2c84b8004..67156dcecc 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -10,18 +10,21 @@ license = "MIT OR Apache-2.0" lazy_static = "1.4" ethers = { version = "0.17.0", features = ["ethers-solc"] } serde_json = "1.0.66" -serde = {version = "1.0.130", features = ["derive"] } -bus-mapping = { path = "../bus-mapping"} -eth-types = { path = "../eth-types"} +serde = { version = "1.0.130", features = ["derive"] } +bus-mapping = { path = "../bus-mapping" , features = ["test"] } +eth-types = { path = "../eth-types" } zkevm-circuits = { path = "../zkevm-circuits", features = ["test"] } tokio = { version = "1.13", features = ["macros", "rt-multi-thread"] } url = "2.2.2" pretty_assertions = "1.0.0" log = "0.4.14" env_logger = "0.9" -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_09_10" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } rand_chacha = "0.3" paste = "1.0" +rand_xorshift = "0.3.0" +rand_core = "0.6.4" +mock = { path = "../mock" } [dev-dependencies] pretty_assertions = "1.0.0" @@ -31,3 +34,4 @@ default = [] rpc = [] circuit_input_builder = [] circuits = [] +mock_prover = [] diff --git a/integration-tests/README.md b/integration-tests/README.md index 0b6182e722..a53a0cc1dd 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -11,7 +11,7 @@ is used like this: $ ./run.sh --help Usage: ./run.sh [OPTIONS] Options: - --sudo Use sudo for docker-compose commands. + --sudo Use sudo for docker compose commands. --steps ARG Space separated list of steps to do. Default: "setup gendata tests cleanup". --tests ARG Space separated list of tests to run. @@ -21,7 +21,7 @@ $ ./run.sh --help ## Steps 1. Setup: Start the docker container that runs a fresh geth in dev mode, via - docker-compose. + docker compose. 2. Gendata: Run the `gen_blockchain_data` binary found in `src/bin/gen_blockchain_data.rs` which compiles the contracts, deploys them, and executes transactions; in order to generate blocks with a variety of @@ -45,6 +45,6 @@ themselves are defined in `lib.rs`. ## Requirements The following software needs to be installed to run the integration tests script: -- docker-compose +- docker compose - Rust toolchain - `solc` version 0.7.x or 0.8.x diff --git a/integration-tests/docker-compose.yml b/integration-tests/docker-compose.yml index a1765c6561..f3a5dc75ff 100644 --- a/integration-tests/docker-compose.yml +++ b/integration-tests/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: geth0: - image: "ethereum/client-go:v1.10.18" + image: "ethereum/client-go:v1.11.5" container_name: zkevm-geth0 ports: - 8545:8545 diff --git a/integration-tests/run.sh b/integration-tests/run.sh index ccf8e576a2..a67bdb4902 100755 --- a/integration-tests/run.sh +++ b/integration-tests/run.sh @@ -3,13 +3,13 @@ set -e ARG_DEFAULT_SUDO= ARG_DEFAULT_STEPS="setup gendata tests cleanup" -ARG_DEFAULT_TESTS="rpc circuit_input_builder circuits" +ARG_DEFAULT_TESTS="rpc circuit_input_builder circuits::mock_prover" usage() { cat >&2 << EOF Usage: $0 [OPTIONS] Options: - --sudo Use sudo for docker-compoes commands. + --sudo Use sudo for docker compose commands. --steps ARG Space separated list of steps to do. Default: "${ARG_DEFAULT_STEPS}". --tests ARG Space separated list of tests to run. @@ -76,9 +76,9 @@ done docker_compose_cmd() { if [ -n "$ARG_SUDO" ]; then - sudo docker-compose $@ + sudo docker compose $@ else - docker-compose $@ + docker compose $@ fi } @@ -98,7 +98,7 @@ fi if [ -n "$STEP_TESTS" ]; then for testname in $ARG_TESTS; do echo "+ Running test group $testname" - cargo test --profile release --test $testname --features $testname -- --nocapture + cargo test --profile release --test $(echo $testname | sed -e 's/::/ /g') --all-features -- --nocapture done fi diff --git a/integration-tests/src/bin/gen_blockchain_data.rs b/integration-tests/src/bin/gen_blockchain_data.rs index d1e846fe2d..680b0ab48d 100644 --- a/integration-tests/src/bin/gen_blockchain_data.rs +++ b/integration-tests/src/bin/gen_blockchain_data.rs @@ -1,11 +1,13 @@ use ethers::{ abi::{self, Tokenize}, contract::{builders::ContractCall, Contract, ContractFactory}, - core::types::{ - transaction::eip2718::TypedTransaction, Address, TransactionReceipt, TransactionRequest, - U256, U64, + core::{ + types::{ + transaction::eip2718::TypedTransaction, Address, TransactionReceipt, + TransactionRequest, U256, U64, + }, + utils::WEI_IN_ETHER, }, - core::utils::WEI_IN_ETHER, middleware::SignerMiddleware, providers::{Middleware, PendingTransaction}, signers::Signer, @@ -15,13 +17,8 @@ use integration_tests::{ get_client, get_provider, get_wallet, log_init, CompiledContract, GenDataOutput, CONTRACTS, CONTRACTS_PATH, }; -use log::{debug, info}; -use std::collections::HashMap; -use std::fs::File; -use std::path::Path; -use std::sync::Arc; -use std::thread::sleep; -use std::time::Duration; +use log::{error, info}; +use std::{collections::HashMap, fs::File, path::Path, sync::Arc, thread::sleep, time::Duration}; async fn deploy(prov: Arc, compiled: &CompiledContract, args: T) -> Contract where @@ -83,7 +80,7 @@ async fn main() { let path_sol = Path::new(CONTRACTS_PATH).join(contract_path); let compiled = Solc::default() .compile_source(&path_sol) - .expect("solc compile error"); + .unwrap_or_else(|_| panic!("solc compile error {:?}", path_sol)); if !compiled.errors.is_empty() { panic!("Errors compiling {:?}:\n{:#?}", &path_sol, compiled.errors) } @@ -123,7 +120,7 @@ async fn main() { break; } Err(err) => { - debug!("Geth not available: {:?}", err); + error!("Geth not available: {:?}", err); sleep(Duration::from_millis(500)); } } @@ -147,7 +144,6 @@ async fn main() { let mut blocks = HashMap::new(); - // // ETH Transfer: Transfer funds to our account. // @@ -164,7 +160,6 @@ async fn main() { let block_num = prov.get_block_number().await.expect("cannot get block_num"); blocks.insert("Transfer 0".to_string(), block_num.as_u64()); - // // Deploy smart contracts // @@ -204,7 +199,6 @@ async fn main() { (block_num.as_u64(), contract.address()), ); - // // ETH transfers: Generate a block with multiple transfers // @@ -259,7 +253,6 @@ async fn main() { let block_num = prov.get_block_number().await.expect("cannot get block_num"); blocks.insert("Multiple transfers 0".to_string(), block_num.as_u64()); - // // ERC20 calls (OpenZeppelin) // diff --git a/integration-tests/src/integration_test_circuits.rs b/integration-tests/src/integration_test_circuits.rs new file mode 100644 index 0000000000..4987bbfadd --- /dev/null +++ b/integration-tests/src/integration_test_circuits.rs @@ -0,0 +1,339 @@ +use crate::{get_client, GenDataOutput}; +use bus_mapping::{ + circuit_input_builder::{BuilderClient, CircuitInputBuilder, CircuitsParams}, + mock::BlockData, +}; +use eth_types::geth_types::GethData; +use halo2_proofs::{ + dev::{CellValue, MockProver}, + halo2curves::bn256::{Bn256, Fr, G1Affine}, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, Circuit, ProvingKey, VerifyingKey}, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + }, + transcript::{ + Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, + }, +}; +use lazy_static::lazy_static; +use mock::TestContext; +use rand_chacha::rand_core::SeedableRng; +use rand_core::RngCore; +use rand_xorshift::XorShiftRng; +use std::{collections::HashMap, marker::PhantomData, sync::Mutex}; +use tokio::sync::Mutex as TokioMutex; +use zkevm_circuits::{ + bytecode_circuit::TestBytecodeCircuit, + copy_circuit::TestCopyCircuit, + evm_circuit::TestEvmCircuit, + exp_circuit::TestExpCircuit, + keccak_circuit::TestKeccakCircuit, + state_circuit::TestStateCircuit, + super_circuit::SuperCircuit, + tx_circuit::TestTxCircuit, + util::SubCircuit, + witness::{block_convert, Block}, +}; + +/// TEST_MOCK_RANDOMNESS +const TEST_MOCK_RANDOMNESS: u64 = 0x100; + +/// MAX_TXS +const MAX_TXS: usize = 4; +/// MAX_CALLDATA +const MAX_CALLDATA: usize = 512; +/// MAX_RWS +const MAX_RWS: usize = 5888; +/// MAX_BYTECODE +const MAX_BYTECODE: usize = 5000; +/// MAX_COPY_ROWS +const MAX_COPY_ROWS: usize = 5888; +/// MAX_EVM_ROWS +const MAX_EVM_ROWS: usize = 10000; +/// MAX_EXP_STEPS +const MAX_EXP_STEPS: usize = 1000; + +const MAX_KECCAK_ROWS: usize = 15000; + +const CIRCUITS_PARAMS: CircuitsParams = CircuitsParams { + max_rws: MAX_RWS, + max_txs: MAX_TXS, + max_calldata: MAX_CALLDATA, + max_bytecode: MAX_BYTECODE, + max_copy_rows: MAX_COPY_ROWS, + max_evm_rows: MAX_EVM_ROWS, + max_exp_steps: MAX_EXP_STEPS, + max_keccak_rows: MAX_KECCAK_ROWS, +}; + +const EVM_CIRCUIT_DEGREE: u32 = 18; +const STATE_CIRCUIT_DEGREE: u32 = 17; +const TX_CIRCUIT_DEGREE: u32 = 20; +const BYTECODE_CIRCUIT_DEGREE: u32 = 16; +const COPY_CIRCUIT_DEGREE: u32 = 16; +const KECCAK_CIRCUIT_DEGREE: u32 = 16; +const SUPER_CIRCUIT_DEGREE: u32 = 20; +const EXP_CIRCUIT_DEGREE: u32 = 16; + +lazy_static! { + /// Data generation. + static ref GEN_DATA: GenDataOutput = GenDataOutput::load(); + static ref RNG: XorShiftRng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); +} + +lazy_static! { + static ref GEN_PARAMS: Mutex>> = Mutex::new(HashMap::new()); +} + +lazy_static! { + /// Integration test for EVM circuit + pub static ref EVM_CIRCUIT_TEST: TokioMutex>> = + TokioMutex::new(IntegrationTest::new("EVM", EVM_CIRCUIT_DEGREE)); + + /// Integration test for State circuit + pub static ref STATE_CIRCUIT_TEST: TokioMutex>> = + TokioMutex::new(IntegrationTest::new("State", STATE_CIRCUIT_DEGREE)); + + /// Integration test for State circuit + pub static ref TX_CIRCUIT_TEST: TokioMutex>> = + TokioMutex::new(IntegrationTest::new("Tx", TX_CIRCUIT_DEGREE)); + + /// Integration test for Bytecode circuit + pub static ref BYTECODE_CIRCUIT_TEST: TokioMutex>> = + TokioMutex::new(IntegrationTest::new("Bytecode", BYTECODE_CIRCUIT_DEGREE)); + + /// Integration test for Copy circuit + pub static ref COPY_CIRCUIT_TEST: TokioMutex>> = + TokioMutex::new(IntegrationTest::new("Copy", COPY_CIRCUIT_DEGREE)); + + /// Integration test for Keccak circuit + pub static ref KECCAK_CIRCUIT_TEST: TokioMutex>> = + TokioMutex::new(IntegrationTest::new("Keccak", KECCAK_CIRCUIT_DEGREE)); + + /// Integration test for Copy circuit + pub static ref SUPER_CIRCUIT_TEST: TokioMutex>> = + TokioMutex::new(IntegrationTest::new("Super", SUPER_CIRCUIT_DEGREE)); + + /// Integration test for Exp circuit + pub static ref EXP_CIRCUIT_TEST: TokioMutex>> = + TokioMutex::new(IntegrationTest::new("Exp", EXP_CIRCUIT_DEGREE)); +} + +/// Generic implementation for integration tests +pub struct IntegrationTest + Circuit> { + name: &'static str, + degree: u32, + key: Option>, + fixed: Option>>>, + _marker: PhantomData, +} + +impl + Circuit> IntegrationTest { + fn new(name: &'static str, degree: u32) -> Self { + Self { + name, + degree, + key: None, + fixed: None, + _marker: PhantomData, + } + } + + fn get_key(&mut self) -> ProvingKey { + match self.key.clone() { + Some(key) => key, + None => { + let block = new_empty_block(); + let circuit = C::new_from_block(&block); + let general_params = get_general_params(self.degree); + + let verifying_key = + keygen_vk(&general_params, &circuit).expect("keygen_vk should not fail"); + let key = keygen_pk(&general_params, verifying_key, &circuit) + .expect("keygen_pk should not fail"); + self.key = Some(key.clone()); + key + } + } + } + + fn test_actual(&self, circuit: C, instance: Vec>, proving_key: ProvingKey) { + fn test_gen_proof, R: RngCore>( + rng: R, + circuit: C, + general_params: &ParamsKZG, + proving_key: &ProvingKey, + mut transcript: Blake2bWrite, G1Affine, Challenge255>, + instances: &[&[Fr]], + ) -> Vec { + create_proof::< + KZGCommitmentScheme, + ProverSHPLONK<'_, Bn256>, + Challenge255, + R, + Blake2bWrite, G1Affine, Challenge255>, + C, + >( + general_params, + proving_key, + &[circuit], + &[instances], + rng, + &mut transcript, + ) + .expect("proof generation should not fail"); + + transcript.finalize() + } + + fn test_verify( + general_params: &ParamsKZG, + verifier_params: &ParamsKZG, + verifying_key: &VerifyingKey, + proof: &[u8], + instances: &[&[Fr]], + ) { + let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(proof); + let strategy = SingleStrategy::new(general_params); + + verify_proof::< + KZGCommitmentScheme, + VerifierSHPLONK<'_, Bn256>, + Challenge255, + Blake2bRead<&[u8], G1Affine, Challenge255>, + SingleStrategy<'_, Bn256>, + >( + verifier_params, + verifying_key, + strategy, + &[instances], + &mut verifier_transcript, + ) + .expect("failed to verify circuit"); + } + + let general_params = get_general_params(self.degree); + let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); + + let transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); + + // change instace to slice + let instance: Vec<&[Fr]> = instance.iter().map(|v| v.as_slice()).collect(); + + let proof = test_gen_proof( + RNG.clone(), + circuit, + &general_params, + &proving_key, + transcript, + &instance, + ); + + let verifying_key = proving_key.get_vk(); + test_verify( + &general_params, + &verifier_params, + verifying_key, + &proof, + &instance, + ); + } + + fn test_mock(&mut self, circuit: &C, instance: Vec>) { + let mock_prover = MockProver::::run(self.degree, circuit, instance).unwrap(); + + self.test_variadic(&mock_prover); + + mock_prover + .verify_par() + .expect("mock prover verification failed"); + } + + fn test_variadic(&mut self, mock_prover: &MockProver) { + let fixed = mock_prover.fixed(); + + match self.fixed.clone() { + Some(prev_fixed) => { + assert!( + fixed.eq(&prev_fixed), + "circuit fixed columns are not constant for different witnesses" + ); + } + None => { + self.fixed = Some(fixed.clone()); + } + }; + + // TODO: check mock_prover.permutation(), currently the returning type + // is private so cannot store. + } + + /// Run integration test at a block identified by a tag. + pub async fn test_at_block_tag(&mut self, block_tag: &str, actual: bool) { + let block_num = *GEN_DATA.blocks.get(block_tag).unwrap(); + let (builder, _) = gen_inputs(block_num).await; + + log::info!( + "test {} circuit, block: #{} - {}", + self.name, + block_num, + block_tag + ); + let mut block = block_convert(&builder.block, &builder.code_db).unwrap(); + block.randomness = Fr::from(TEST_MOCK_RANDOMNESS); + let circuit = C::new_from_block(&block); + let instance = circuit.instance(); + + if actual { + let key = self.get_key(); + self.test_actual(circuit, instance, key); + } else { + self.test_mock(&circuit, instance); + } + } +} + +fn new_empty_block() -> Block { + let block: GethData = TestContext::<0, 0>::new(None, |_| {}, |_, _| {}, |b, _| b) + .unwrap() + .into(); + let mut builder = BlockData::new_from_geth_data_with_params(block.clone(), CIRCUITS_PARAMS) + .new_circuit_input_builder(); + builder + .handle_block(&block.eth_block, &block.geth_traces) + .unwrap(); + block_convert(&builder.block, &builder.code_db).unwrap() +} + +fn get_general_params(degree: u32) -> ParamsKZG { + let mut map = GEN_PARAMS.lock().unwrap(); + match map.get(°ree) { + Some(params) => params.clone(), + None => { + let params = ParamsKZG::::setup(degree, RNG.clone()); + map.insert(degree, params.clone()); + params + } + } +} + +/// returns gen_inputs for a block number +async fn gen_inputs( + block_num: u64, +) -> ( + CircuitInputBuilder, + eth_types::Block, +) { + let cli = get_client(); + let cli = BuilderClient::new(cli, CIRCUITS_PARAMS).await.unwrap(); + + cli.gen_inputs(block_num).await.unwrap() +} diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs index 2d50019539..5eeedf6a6d 100644 --- a/integration-tests/src/lib.rs +++ b/integration-tests/src/lib.rs @@ -8,18 +8,19 @@ use env_logger::Env; use eth_types::Address; use ethers::{ abi, - core::k256::ecdsa::SigningKey, - core::types::Bytes, + core::{k256::ecdsa::SigningKey, types::Bytes}, providers::{Http, Provider}, signers::{coins_bip39::English, MnemonicBuilder, Signer, Wallet}, }; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::env::{self, VarError}; -use std::fs::File; -use std::sync::Once; -use std::time::Duration; +use std::{ + collections::HashMap, + env::{self, VarError}, + fs::File, + sync::Once, + time::Duration, +}; use url::Url; /// Geth dev chain ID @@ -137,3 +138,6 @@ pub struct CompiledContract { /// Runtime Bytecode pub bin_runtime: Bytes, } + +/// Common code for integration tests of circuits. +pub mod integration_test_circuits; diff --git a/integration-tests/tests/circuit_input_builder.rs b/integration-tests/tests/circuit_input_builder.rs index 5ce34d18eb..05c4994501 100644 --- a/integration-tests/tests/circuit_input_builder.rs +++ b/integration-tests/tests/circuit_input_builder.rs @@ -1,6 +1,8 @@ #![cfg(feature = "circuit_input_builder")] -use bus_mapping::circuit_input_builder::BuilderClient; +use bus_mapping::circuit_input_builder::{ + build_state_code_db, get_state_accesses, BuilderClient, CircuitsParams, +}; use integration_tests::{get_client, log_init, GenDataOutput}; use lazy_static::lazy_static; use log::trace; @@ -11,26 +13,48 @@ lazy_static! { async fn test_circuit_input_builder_block(block_num: u64) { let cli = get_client(); - let cli = BuilderClient::new(cli).await.unwrap(); + let cli = BuilderClient::new( + cli, + CircuitsParams { + max_rws: 16384, + max_txs: 1, + max_calldata: 4000, + max_bytecode: 4000, + max_copy_rows: 16384, + max_evm_rows: 0, + max_exp_steps: 1000, + max_keccak_rows: 0, + }, + ) + .await + .unwrap(); // 1. Query geth for Block, Txs and TxExecTraces - let (eth_block, geth_trace) = cli.get_block(block_num).await.unwrap(); + let (eth_block, geth_trace, history_hashes, prev_state_root) = + cli.get_block(block_num).await.unwrap(); // 2. Get State Accesses from TxExecTraces - let access_set = cli.get_state_accesses(ð_block, &geth_trace).unwrap(); + let access_set = get_state_accesses(ð_block, &geth_trace).unwrap(); trace!("AccessSet: {:#?}", access_set); // 3. Query geth for all accounts, storage keys, and codes from Accesses let (proofs, codes) = cli.get_state(block_num, access_set).await.unwrap(); // 4. Build a partial StateDB from step 3 - let (state_db, code_db) = cli.build_state_code_db(proofs, codes); + let (state_db, code_db) = build_state_code_db(proofs, codes); trace!("StateDB: {:#?}", state_db); // 5. For each step in TxExecTraces, gen the associated ops and state // circuit inputs let builder = cli - .gen_inputs_from_state(state_db, code_db, ð_block, &geth_trace) + .gen_inputs_from_state( + state_db, + code_db, + ð_block, + &geth_trace, + history_hashes, + prev_state_root, + ) .unwrap(); trace!("CircuitInputBuilder: {:#?}", builder); diff --git a/integration-tests/tests/circuits.rs b/integration-tests/tests/circuits.rs index 293b22b73a..bfce518a62 100644 --- a/integration-tests/tests/circuits.rs +++ b/integration-tests/tests/circuits.rs @@ -1,199 +1,101 @@ -#![cfg(feature = "circuits")] +macro_rules! run_test { + ($test_instance:expr, $block_tag:expr, $real_prover:expr) => { + log_init(); -use bus_mapping::circuit_input_builder::BuilderClient; -use bus_mapping::operation::OperationContainer; -use eth_types::geth_types; -use halo2_proofs::{ - arithmetic::CurveAffine, - dev::MockProver, - halo2curves::{ - bn256::Fr, - group::{Curve, Group}, - }, -}; -use integration_tests::{get_client, log_init, GenDataOutput, CHAIN_ID}; -use lazy_static::lazy_static; -use log::trace; -use paste::paste; -use rand_chacha::rand_core::SeedableRng; -use rand_chacha::ChaCha20Rng; -use std::marker::PhantomData; -use zkevm_circuits::bytecode_circuit::dev::test_bytecode_circuit; -use zkevm_circuits::copy_circuit::dev::test_copy_circuit; -use zkevm_circuits::evm_circuit::witness::RwMap; -use zkevm_circuits::evm_circuit::{test::run_test_circuit, witness::block_convert}; -use zkevm_circuits::state_circuit::StateCircuit; -use zkevm_circuits::tx_circuit::{sign_verify::SignVerifyChip, Secp256k1Affine, TxCircuit}; - -lazy_static! { - pub static ref GEN_DATA: GenDataOutput = GenDataOutput::load(); -} - -async fn test_evm_circuit_block(block_num: u64) { - log::info!("test evm circuit, block number: {}", block_num); - let cli = get_client(); - let cli = BuilderClient::new(cli).await.unwrap(); - let (builder, _) = cli.gen_inputs(block_num).await.unwrap(); - - let block = block_convert(&builder.block, &builder.code_db); - run_test_circuit(block).expect("evm_circuit verification failed"); -} - -async fn test_state_circuit_block(block_num: u64) { - log::info!("test state circuit, block number: {}", block_num); - let cli = get_client(); - let cli = BuilderClient::new(cli).await.unwrap(); - let (builder, _) = cli.gen_inputs(block_num).await.unwrap(); - - // Generate state proof - let stack_ops = builder.block.container.sorted_stack(); - trace!("stack_ops: {:#?}", stack_ops); - let memory_ops = builder.block.container.sorted_memory(); - trace!("memory_ops: {:#?}", memory_ops); - let storage_ops = builder.block.container.sorted_storage(); - trace!("storage_ops: {:#?}", storage_ops); - - const DEGREE: usize = 17; - - let rw_map = RwMap::from(&OperationContainer { - memory: memory_ops, - stack: stack_ops, - storage: storage_ops, - ..Default::default() - }); - - let randomness = Fr::from(0xcafeu64); - let circuit = StateCircuit::::new(randomness, rw_map, 1 << 16); - let power_of_randomness = circuit.instance(); - - let prover = MockProver::::run(DEGREE as u32, &circuit, power_of_randomness).unwrap(); - prover.verify().expect("state_circuit verification failed"); -} - -async fn test_tx_circuit_block(block_num: u64) { - const DEGREE: u32 = 20; - - log::info!("test tx circuit, block number: {}", block_num); - let cli = get_client(); - let cli = BuilderClient::new(cli).await.unwrap(); - - let (_, eth_block) = cli.gen_inputs(block_num).await.unwrap(); - let txs: Vec<_> = eth_block - .transactions - .iter() - .map(geth_types::Transaction::from) - .collect(); - - let mut rng = ChaCha20Rng::seed_from_u64(2); - let aux_generator = ::CurveExt::random(&mut rng).to_affine(); - - let circuit = TxCircuit:: { - sign_verify: SignVerifyChip { - aux_generator, - window_size: 2, - _marker: PhantomData, - }, - txs, - chain_id: CHAIN_ID, + let mut test = $test_instance.lock().await; + test.test_at_block_tag($block_tag, $real_prover).await; }; - - let prover = MockProver::run(DEGREE, &circuit, vec![vec![]]).unwrap(); - - prover.verify().expect("tx_circuit verification failed"); -} - -pub async fn test_bytecode_circuit_block(block_num: u64) { - const DEGREE: u32 = 16; - - log::info!("test bytecode circuit, block number: {}", block_num); - let cli = get_client(); - let cli = BuilderClient::new(cli).await.unwrap(); - let (builder, _) = cli.gen_inputs(block_num).await.unwrap(); - let bytecodes: Vec> = builder.code_db.0.values().cloned().collect(); - - test_bytecode_circuit::(DEGREE, bytecodes); -} - -pub async fn test_copy_circuit_block(block_num: u64) { - const DEGREE: u32 = 16; - - log::info!("test copy circuit, block number: {}", block_num); - let cli = get_client(); - let cli = BuilderClient::new(cli).await.unwrap(); - let (builder, _) = cli.gen_inputs(block_num).await.unwrap(); - let block = block_convert(&builder.block, &builder.code_db); - - assert!(test_copy_circuit(DEGREE, block).is_ok()); } macro_rules! declare_tests { - ($name:ident, $block_tag:expr) => { + (($name:ident, $block_tag:expr),$real_prover:expr) => { paste! { #[tokio::test] async fn []() { - log_init(); - let block_num = GEN_DATA.blocks.get($block_tag).unwrap(); - test_evm_circuit_block(*block_num).await; + run_test! (EVM_CIRCUIT_TEST, $block_tag, $real_prover); } #[tokio::test] async fn []() { - log_init(); - let block_num = GEN_DATA.blocks.get($block_tag).unwrap(); - test_state_circuit_block(*block_num).await; + run_test! (STATE_CIRCUIT_TEST, $block_tag, $real_prover); } #[tokio::test] async fn []() { - log_init(); - let block_num = GEN_DATA.blocks.get($block_tag).unwrap(); - test_tx_circuit_block(*block_num).await; + run_test! (TX_CIRCUIT_TEST, $block_tag, $real_prover); } #[tokio::test] async fn []() { - log_init(); - let block_num = GEN_DATA.blocks.get($block_tag).unwrap(); - test_bytecode_circuit_block(*block_num).await; + run_test! (BYTECODE_CIRCUIT_TEST, $block_tag, $real_prover); } #[tokio::test] async fn []() { - log_init(); - let block_num = GEN_DATA.blocks.get($block_tag).unwrap(); - test_copy_circuit_block(*block_num).await; + run_test! (COPY_CIRCUIT_TEST, $block_tag, $real_prover); } + #[tokio::test] + async fn []() { + run_test! (KECCAK_CIRCUIT_TEST, $block_tag, $real_prover); + } + + #[tokio::test] + async fn []() { + run_test! (SUPER_CIRCUIT_TEST, $block_tag, $real_prover); + } + + #[tokio::test] + async fn []() { + run_test! (EXP_CIRCUIT_TEST, $block_tag, $real_prover); + } } }; } -/* -declare_tests!( - test_evm_circuit_block_transfer_0, - test_state_circuit_block_transfer_0, - "Transfer 0" -); -declare_tests!( - test_evm_circuit_deploy_greeter, - test_state_circuit_deploy_greeter, - "Deploy Greeter" -); -declare_tests!( - test_evm_circuit_multiple_transfers_0, - test_state_circuit_multiple_transfers_0, - "Multiple transfers 0" -); -*/ -declare_tests!( - circuit_erc20_openzeppelin_transfer_fail, - "ERC20 OpenZeppelin transfer failed" -); -declare_tests!( - circuit_erc20_openzeppelin_transfer_succeed, - "ERC20 OpenZeppelin transfer successful" -); -declare_tests!( - circuit_multiple_erc20_openzeppelin_transfers, - "Multiple ERC20 OpenZeppelin transfers" +macro_rules! unroll_tests { + ($($arg:tt),*) => { + use paste::paste; + use integration_tests::integration_test_circuits::{ + EVM_CIRCUIT_TEST, + STATE_CIRCUIT_TEST, + TX_CIRCUIT_TEST, + BYTECODE_CIRCUIT_TEST, + COPY_CIRCUIT_TEST, + KECCAK_CIRCUIT_TEST, + SUPER_CIRCUIT_TEST, + EXP_CIRCUIT_TEST + }; + use integration_tests::log_init; + mod real_prover { + use super::*; + $( + declare_tests! ($arg, true) ; + )* + } + + mod mock_prover { + use super::*; + $( + declare_tests! ($arg, false) ; + )* + } + } +} + +unroll_tests!( + (circuit_block_transfer_0, "Transfer 0"), + (circuit_multiple_transfers_0, "Multiple transfers 0"), + ( + circuit_erc20_openzeppelin_transfer_fail, + "ERC20 OpenZeppelin transfer failed" + ), + ( + circuit_erc20_openzeppelin_transfer_succeed, + "ERC20 OpenZeppelin transfer successful" + ), + ( + circuit_multiple_erc20_openzeppelin_transfers, + "Multiple ERC20 OpenZeppelin transfers" + ) ); diff --git a/integration-tests/tests/rpc.rs b/integration-tests/tests/rpc.rs index bfc1cd9237..9285c9b411 100644 --- a/integration-tests/tests/rpc.rs +++ b/integration-tests/tests/rpc.rs @@ -4,8 +4,7 @@ use eth_types::{StorageProof, Word}; use integration_tests::{get_client, CompiledContract, GenDataOutput, CHAIN_ID, CONTRACTS_PATH}; use lazy_static::lazy_static; use pretty_assertions::assert_eq; -use std::fs::File; -use std::path::Path; +use std::{fs::File, path::Path}; lazy_static! { pub static ref GEN_DATA: GenDataOutput = GenDataOutput::load(); diff --git a/keccak256/Cargo.toml b/keccak256/Cargo.toml index 870b42ab90..490dc87063 100644 --- a/keccak256/Cargo.toml +++ b/keccak256/Cargo.toml @@ -15,6 +15,8 @@ num-traits = "0.2.14" plotters = { version = "0.3.0", optional = true } eth-types = { path = "../eth-types" } lazy_static = "1.4" +log = "0.4.14" +env_logger = "0.9" [dev-dependencies] pretty_assertions = "1.0" diff --git a/keccak256/src/arith_helpers.rs b/keccak256/src/arith_helpers.rs index 9504c4befe..4877486b08 100644 --- a/keccak256/src/arith_helpers.rs +++ b/keccak256/src/arith_helpers.rs @@ -1,6 +1,7 @@ use crate::common::State; use eth_types::Field; use itertools::Itertools; +use log::debug; use num_bigint::BigUint; use num_traits::Zero; use std::ops::{Index, IndexMut}; @@ -192,13 +193,13 @@ pub fn inspect(x: BigUint, name: &str, base: u8) { let mut chunks = x.to_radix_le(base.into()); chunks.resize(65, 0); let info: Vec<(usize, u8)> = (0..65).zip(chunks.iter().copied()).collect_vec(); - println!("inspect {} {} info {:?}", name, x, info); + debug!("inspect {} {} info {:?}", name, x, info); } pub fn f_from_radix_be(buf: &[u8], base: u8) -> F { let base = F::from(base as u64); buf.iter() - .fold(F::zero(), |acc, &x| acc * base + F::from(x as u64)) + .fold(F::ZERO, |acc, &x| acc * base + F::from(x as u64)) } #[cfg(test)] diff --git a/keccak256/src/keccak_arith.rs b/keccak256/src/keccak_arith.rs index 4fe228350a..c59b0964f3 100644 --- a/keccak256/src/keccak_arith.rs +++ b/keccak256/src/keccak_arith.rs @@ -1,5 +1,4 @@ -use crate::arith_helpers::*; -use crate::common::*; +use crate::{arith_helpers::*, common::*}; use itertools::Itertools; #[derive(Default)] @@ -231,9 +230,11 @@ impl Sponge { } #[cfg(test)] mod tests { - use crate::arith_helpers::*; - use crate::keccak_arith::{Keccak, KeccakFArith, State}; - use crate::plain::KeccakF; + use crate::{ + arith_helpers::*, + keccak_arith::{Keccak, KeccakFArith, State}, + plain::KeccakF, + }; use itertools::Itertools; use num_bigint::BigUint; use num_traits::Zero; @@ -253,7 +254,10 @@ mod tests { convert_b13_lane_to_b9(BigUint::from(170u64), 0), BigUint::from(82u64) ); - assert_eq!(convert_b9_lane_to_b13(BigUint::from(82u64)), Zero::zero()); + assert_eq!( + convert_b9_lane_to_b13(BigUint::from(82u64)), + BigUint::zero() + ); assert_eq!(convert_b9_lane_to_b2(BigUint::from(82u64)), 0); assert_eq!( convert_b9_lane_to_b2(BigUint::from(9u64).pow(63) * 2u64), diff --git a/keccak256/src/lib.rs b/keccak256/src/lib.rs index f94cdeb29e..986db13d17 100644 --- a/keccak256/src/lib.rs +++ b/keccak256/src/lib.rs @@ -8,15 +8,3 @@ pub mod gate_helpers; pub mod keccak_arith; // We build plain module for the purpose of reviewing the circuit pub mod plain; - -lazy_static::lazy_static! { - pub static ref EMPTY_HASH: [u8; 32] = { - let mut keccak = plain::Keccak::default(); - keccak.update(&[]); - keccak.digest().try_into().unwrap() - }; - pub static ref EMPTY_HASH_LE: [u8; 32] = { - use itertools::Itertools; - EMPTY_HASH.iter().rev().cloned().collect_vec().try_into().unwrap() - }; -} diff --git a/keccak256/src/plain.rs b/keccak256/src/plain.rs index 3a11c0f302..8540479505 100644 --- a/keccak256/src/plain.rs +++ b/keccak256/src/plain.rs @@ -4,6 +4,7 @@ use itertools::Itertools; pub struct Keccak { state: State, sponge: Sponge, + scratch: Vec, } impl Default for Keccak { @@ -14,29 +15,53 @@ impl Default for Keccak { state: [[0; 5]; 5], // rate & capacity in bytes sponge: Sponge::new(security_level.0 / 8, security_level.1 / 8), + scratch: Vec::new(), } } } impl Keccak { pub fn update(&mut self, input: &[u8]) { - let padding_total = self.sponge.rate - (input.len() % self.sponge.rate); - let mut padding: Vec; + let rate = self.sponge.rate; + // offset for `input` + let mut offset = 0; + + let scratch_len = self.scratch.len(); + if scratch_len > 0 && scratch_len + input.len() >= rate { + // concat scratch and input up to the next full `rate` + offset = rate - scratch_len; + self.scratch.extend(&input[0..offset]); + self.sponge.absorb(&mut self.state, &self.scratch); + self.scratch.truncate(0); + } - if padding_total == 1 { - padding = vec![0x81]; - } else { - padding = vec![0x01]; - padding.resize(padding_total - 1, 0x00); - padding.push(0x80); + let chunks_total = (input.len() - offset) / rate; + if chunks_total != 0 { + // absorb all chunks + let tail = offset + (rate * chunks_total); + self.sponge.absorb(&mut self.state, &input[offset..tail]); + offset = tail; } - let padded_input: &[u8] = &[input, &padding].concat(); - self.sponge.absorb(&mut self.state, padded_input); + if offset != input.len() { + // save the remainder + self.scratch.extend(&input[offset..]); + } } /// Returns keccak hash based on current state pub fn digest(&mut self) -> Vec { + let len = self.scratch.len(); + let padding_total = self.sponge.rate - (len % self.sponge.rate); + if padding_total == 1 { + self.scratch.push(0x81); + } else { + self.scratch.push(0x01); + self.scratch.resize(len + padding_total - 1, 0x00); + self.scratch.push(0x80); + } + self.sponge.absorb(&mut self.state, &self.scratch); + self.scratch.truncate(0); self.sponge.squeeze(&mut self.state) } } @@ -185,7 +210,17 @@ impl Sponge { fn keccak256(msg: &[u8]) -> Vec { let mut keccak = Keccak::default(); keccak.update(msg); - keccak.digest() + let a = keccak.digest(); + + let mut keccak = Keccak::default(); + for byte in msg { + keccak.update(&[*byte]); + } + let b = keccak.digest(); + + assert_eq!(a, b); + + a } #[test] diff --git a/mock/src/account.rs b/mock/src/account.rs index 0cdda75549..87abb710e8 100644 --- a/mock/src/account.rs +++ b/mock/src/account.rs @@ -11,7 +11,7 @@ pub struct MockAccount { /// Address pub address: Address, /// nonce - pub nonce: Word, + pub nonce: u64, /// Balance pub balance: Word, /// EVM Code @@ -24,7 +24,7 @@ impl From for Account { fn from(mock: MockAccount) -> Self { Account { address: mock.address, - nonce: mock.nonce, + nonce: mock.nonce.into(), balance: mock.balance, code: mock.code, storage: mock.storage, @@ -40,7 +40,7 @@ impl MockAccount { } /// Set nonce field for the MockAccount. - pub fn nonce(&mut self, nonce: Word) -> &mut Self { + pub fn nonce(&mut self, nonce: u64) -> &mut Self { self.nonce = nonce; self } @@ -69,7 +69,7 @@ impl MockAccount { /// Set all fields for the MockAccount based on their values in `account`. pub fn account(&mut self, account: &Account) -> &mut Self { self.address(account.address); - self.nonce(account.nonce); + self.nonce(account.nonce.as_u64()); self.balance(account.balance); self.code(account.code.clone()); self.storage(account.storage.iter().map(|(k, v)| (*k, *v))); diff --git a/mock/src/block.rs b/mock/src/block.rs index 3ad79e098d..4123312933 100644 --- a/mock/src/block.rs +++ b/mock/src/block.rs @@ -1,9 +1,8 @@ //! Mock Block definition and builder related methods. -use crate::{MockTransaction, MOCK_CHAIN_ID}; +use crate::{MockTransaction, MOCK_BASEFEE, MOCK_CHAIN_ID, MOCK_DIFFICULTY, MOCK_GASLIMIT}; use eth_types::{Address, Block, Bytes, Hash, Transaction, Word, H64, U64}; -use ethers_core::types::Bloom; -use ethers_core::types::OtherFields; +use ethers_core::types::{Bloom, OtherFields}; #[derive(Clone, Debug)] /// Mock structure which represents an Ethereum Block and can be used for tests. @@ -50,12 +49,12 @@ impl Default for MockBlock { receipts_root: Hash::zero(), number: U64([0u64]), gas_used: Word::zero(), - gas_limit: Word::from(0x2386f26fc10000u64), - base_fee_per_gas: Word::zero(), + gas_limit: *MOCK_GASLIMIT, + base_fee_per_gas: *MOCK_BASEFEE, extra_data: Bytes::default(), logs_bloom: None, timestamp: Word::from(123456789u64), - difficulty: Word::from(0x200000u64), + difficulty: *MOCK_DIFFICULTY, total_difficulty: Word::zero(), seal_fields: Vec::new(), uncles: Vec::new(), diff --git a/mock/src/lib.rs b/mock/src/lib.rs index fe495202e2..f190e0612c 100644 --- a/mock/src/lib.rs +++ b/mock/src/lib.rs @@ -1,6 +1,6 @@ //! Mock types and functions to generate GethData used for tests -use eth_types::{address, Address, Word}; +use eth_types::{address, bytecode, bytecode::Bytecode, word, Address, Bytes, Word}; use ethers_signers::LocalWallet; use lazy_static::lazy_static; use rand::SeedableRng; @@ -16,13 +16,21 @@ pub use test_ctx::TestContext; pub use transaction::{AddrOrWallet, MockTransaction, CORRECT_MOCK_TXS}; lazy_static! { + /// Mock 1 ETH + pub static ref MOCK_1_ETH: Word = eth(1); /// Mock coinbase value pub static ref MOCK_COINBASE: Address = address!("0x00000000000000000000000000000000c014ba5e"); /// Mock gasprice value pub static ref MOCK_GASPRICE: Word = Word::from(1u8); + /// Mock BASEFEE value + pub static ref MOCK_BASEFEE: Word = Word::zero(); + /// Mock GASLIMIT value + pub static ref MOCK_GASLIMIT: Word = Word::from(0x2386f26fc10000u64); /// Mock chain ID value pub static ref MOCK_CHAIN_ID: Word = Word::from(1338u64); + /// Mock DIFFICULTY value + pub static ref MOCK_DIFFICULTY: Word = Word::from(0x200000u64); /// Mock accounts loaded with ETH to use for test cases. pub static ref MOCK_ACCOUNTS: Vec
= vec![ address!("0x000000000000000000000000000000000cafe111"), @@ -31,6 +39,15 @@ lazy_static! { address!("0x000000000000000000000000000000000cafe444"), address!("0x000000000000000000000000000000000cafe555"), ]; + /// Mock EVM codes to use for test cases. + pub static ref MOCK_CODES: Vec = vec![ + Bytes::from([0x60, 0x10, 0x00]), // PUSH1(0x10), STOP + Bytes::from([0x60, 0x01, 0x60, 0x02, 0x01, 0x00]), // PUSH1(1), PUSH1(2), ADD, STOP + Bytes::from([0x60, 0x01, 0x60, 0x02, 0x02, 0x00]), // PUSH1(1), PUSH1(2), MUL, STOP + Bytes::from([0x60, 0x02, 0x60, 0x01, 0x03, 0x00]), // PUSH1(2), PUSH1(1), SUB, STOP + Bytes::from([0x60, 0x09, 0x60, 0x03, 0x04, 0x00]), // PUSH1(9), PUSH1(3), DIV, STOP + Bytes::from([0x30; 256]), // ADDRESS * 256 + ]; /// Mock wallets used to generate correctly signed and hashed Transactions. pub static ref MOCK_WALLETS: Vec = { let mut rng = ChaCha20Rng::seed_from_u64(2u64); @@ -40,6 +57,27 @@ lazy_static! { LocalWallet::new(&mut rng), ] }; + /// Mock EVM bytecode for a deployed contract. + /// PUSH1 0x20 + /// PUSH1 0 + /// PUSH1 0 + /// CALLDATACOPY + /// PUSH1 0x20 + /// PUSH1 0 + /// RETURN + /// + /// bytecode: 0x6020600060003760206000F3 + /// + /// // constructor + /// PUSH12 0x6020600060003760206000F3 + /// PUSH1 0 + /// MSTORE + /// PUSH1 0xC + /// PUSH1 0x14 + /// RETURN + /// + /// bytecode: 0x6B6020600060003760206000F3600052600C6014F3 + pub static ref MOCK_DEPLOYED_CONTRACT_BYTECODE: Word = word!("6B6020600060003760206000F3600052600C6014F3"); } /// Generate a [`Word`] which corresponds to a certain amount of ETH. @@ -51,3 +89,60 @@ pub fn eth(x: u64) -> Word { pub fn gwei(x: u64) -> Word { Word::from(x) * Word::from(10u64.pow(9)) } + +/// Holds the parameters for generating mock EVM bytecode for a contract call +pub struct MockCallBytecodeParams { + /// The address to call with the generated bytecode + pub address: Address, + /// The data to be passed as arguments to the contract function. + pub pushdata: Vec, + /// The offset in memory where the return data will be stored. + pub return_data_offset: usize, + /// The size of the return data. + pub return_data_size: usize, + /// The length of the call data. + pub call_data_length: usize, + /// The offset in memory where the call data will be stored. + pub call_data_offset: usize, + /// The amount of gas to be used for the contract call. + pub gas: u64, + /// The instructions to be executed after the contract call. + pub instructions_after_call: Bytecode, +} + +/// Set default parameters for MockCallBytecodeParams +impl Default for MockCallBytecodeParams { + fn default() -> Self { + MockCallBytecodeParams { + address: address!("0x0000000000000000000000000000000000000000"), + pushdata: Vec::new(), + return_data_offset: 0x00usize, + return_data_size: 0x00usize, + call_data_length: 0x00usize, + call_data_offset: 0x00usize, + gas: 0x1_0000u64, + instructions_after_call: Bytecode::default(), + } + } +} + +/// Generate mock EVM bytecode that performs a contract call +pub fn generate_mock_call_bytecode(params: MockCallBytecodeParams) -> Bytecode { + bytecode! { + .op_mstore( + 0u64, + Word::from_big_endian(¶ms.pushdata) + ) + .op_call( + params.gas, + params.address, + 0u64, + params.call_data_offset, + params.call_data_length, + params.return_data_size, + params.return_data_offset, + ) + .append(¶ms.instructions_after_call) + STOP + } +} diff --git a/mock/src/test_ctx.rs b/mock/src/test_ctx.rs index e11557fa2f..4c70d309c4 100644 --- a/mock/src/test_ctx.rs +++ b/mock/src/test_ctx.rs @@ -66,7 +66,7 @@ pub use external_tracer::LoggerConfig; /// txs[1] /// .to(accs[1].address) /// .from(accs[2].address) -/// .nonce(Word::one()); +/// .nonce(1); /// }, /// |block, _tx| block.number(0xcafeu64), /// ) @@ -76,7 +76,7 @@ pub use external_tracer::LoggerConfig; /// // Now we can start generating the traces and items we need to inspect /// // the behaviour of the generated env. /// ``` -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TestContext { /// chain id pub chain_id: Word, @@ -88,7 +88,7 @@ pub struct TestContext { /// Block from geth pub eth_block: eth_types::Block, /// Execution Trace from geth - pub geth_traces: [eth_types::GethExecTrace; NTX], + pub geth_traces: Vec, } impl From> for GethData { @@ -141,10 +141,8 @@ impl TestContext { .enumerate() .skip(1) .for_each(|(idx, tx)| { - tx.transaction_idx(u64::try_from(idx).expect("Unexpected idx conversion error")); - tx.nonce(Word::from( - u64::try_from(idx).expect("Unexpected idx conversion error"), - )); + let idx = u64::try_from(idx).expect("Unexpected idx conversion error"); + tx.transaction_idx(idx).nonce(idx); }); let tx_refs = transactions.iter_mut().collect(); @@ -171,7 +169,7 @@ impl TestContext { let geth_traces = gen_geth_traces( chain_id, block.clone(), - accounts.clone(), + accounts.to_vec(), history_hashes.clone(), logger_config, )?; @@ -228,13 +226,13 @@ impl TestContext { /// Generates execution traces for the transactions included in the provided /// Block -fn gen_geth_traces( +pub fn gen_geth_traces( chain_id: Word, block: Block, - accounts: [Account; NACC], + accounts: Vec, history_hashes: Option>, logger_config: LoggerConfig, -) -> Result<[GethExecTrace; NTX], Error> { +) -> Result, Error> { let trace_config = TraceConfig { chain_id, history_hashes: history_hashes.unwrap_or_default(), @@ -251,8 +249,7 @@ fn gen_geth_traces( logger_config, }; let traces = trace(&trace_config)?; - let result: [GethExecTrace; NTX] = traces.try_into().expect("Unexpected len mismatch"); - Ok(result) + Ok(traces) } /// Collection of helper functions which contribute to specific rutines on the diff --git a/mock/src/transaction.rs b/mock/src/transaction.rs index c96fd23826..1b6c6ccd1f 100644 --- a/mock/src/transaction.rs +++ b/mock/src/transaction.rs @@ -1,15 +1,13 @@ //! Mock Transaction definition and builder related methods. use super::{MOCK_ACCOUNTS, MOCK_CHAIN_ID, MOCK_GASPRICE}; -use eth_types::word; use eth_types::{ - geth_types::Transaction as GethTransaction, AccessList, Address, Bytes, Hash, Transaction, - Word, U64, + geth_types::Transaction as GethTransaction, word, AccessList, Address, Bytes, Hash, + Transaction, Word, U64, }; -use ethers_core::types::OtherFields; use ethers_core::{ rand::{CryptoRng, RngCore}, - types::TransactionRequest, + types::{OtherFields, TransactionRequest}, }; use ethers_signers::{LocalWallet, Signer}; use lazy_static::lazy_static; @@ -25,7 +23,7 @@ lazy_static! { vec![MockTransaction::default() .from(AddrOrWallet::random(&mut rng)) .to(MOCK_ACCOUNTS[0]) - .nonce(word!("0x103")) + .nonce(0x103u64) .value(word!("0x3e8")) .gas_price(word!("0x4d2")) .input(Bytes::from(b"hello")) @@ -33,7 +31,7 @@ lazy_static! { MockTransaction::default() .from(AddrOrWallet::random(&mut rng)) .to(MOCK_ACCOUNTS[1]) - .nonce(word!("0x104")) + .nonce(0x104u64) .value(word!("0x3e8")) .gas_price(word!("0x4d2")) .input(Bytes::from(b"hello")) @@ -41,11 +39,19 @@ lazy_static! { MockTransaction::default() .from(AddrOrWallet::random(&mut rng)) .to(MOCK_ACCOUNTS[2]) - .nonce(word!("0x105")) + .nonce(0x105u64) .value(word!("0x3e8")) .gas_price(word!("0x4d2")) .input(Bytes::from(b"hello")) - .build()] + .build(), + MockTransaction::default() + .from(AddrOrWallet::random(&mut rng)) + .to(MOCK_ACCOUNTS[0]) + .nonce(0x106u64) + .value(word!("0x3e8")) + .gas_price(word!("0x4d2")) + .input(Bytes::from(b"hello")) + .build(),] }; } @@ -113,7 +119,7 @@ impl AddrOrWallet { /// any of it's details. pub struct MockTransaction { pub hash: Option, - pub nonce: Word, + pub nonce: u64, pub block_hash: Hash, pub block_number: U64, pub transaction_index: U64, @@ -137,7 +143,7 @@ impl Default for MockTransaction { fn default() -> Self { MockTransaction { hash: None, - nonce: Word::zero(), + nonce: 0, block_hash: Hash::zero(), block_number: U64::zero(), transaction_index: U64::zero(), @@ -163,7 +169,7 @@ impl From for Transaction { fn from(mock: MockTransaction) -> Self { Transaction { hash: mock.hash.unwrap_or_default(), - nonce: mock.nonce, + nonce: mock.nonce.into(), block_hash: Some(mock.block_hash), block_number: Some(mock.block_number), transaction_index: Some(mock.transaction_index), @@ -201,7 +207,7 @@ impl MockTransaction { } /// Set nonce field for the MockTransaction. - pub fn nonce(&mut self, nonce: Word) -> &mut Self { + pub fn nonce(&mut self, nonce: u64) -> &mut Self { self.nonce = nonce; self } diff --git a/rust-toolchain b/rust-toolchain index 24b6d11f20..b6ce6a50ba 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2022-08-23 +nightly-2023-04-24 diff --git a/rustfmt.toml b/rustfmt.toml index 22f8bbbcbe..526145466c 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,9 @@ -max_width = 100 -wrap_comments = true edition = "2021" + +comment_width = 100 +imports_granularity = "Crate" +max_width = 100 +newline_style = "Unix" +normalize_comments = true +reorder_imports = true +wrap_comments = true \ No newline at end of file diff --git a/testool/Cargo.toml b/testool/Cargo.toml index 2f02c85299..5b4faed255 100644 --- a/testool/Cargo.toml +++ b/testool/Cargo.toml @@ -20,7 +20,7 @@ keccak256 = { path = "../keccak256" } log = "0.4" mock = { path = "../mock" } once_cell = "1.10" -prettytable-rs = "0.9" +prettytable-rs = "0.10" rayon = "1.5" regex = "1" serde = { version = "1.0", features = ["derive"] } @@ -31,6 +31,12 @@ thiserror = "1.0" toml = "0.5" yaml-rust = "0.4.5" zkevm-circuits = { path="../zkevm-circuits", features=["test"] } +rand_chacha = "0.3" +rand = "0.8" +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_04_20" } +urlencoding = "2.1.2" + [features] +default = [] ignore-test-docker = [] diff --git a/testool/Config.toml b/testool/Config.toml index 757820f9ec..761bfeb93b 100644 --- a/testool/Config.toml +++ b/testool/Config.toml @@ -1,193 +1,188 @@ +[[suite]] +id="default" +path="tests/src/GeneralStateTestsFiller/**/*" max_gas = 500000 max_steps = 1000 +ignore_tests = [] + +[[suite]] +id="nightly" +path="tests/src/GeneralStateTestsFiller/**/*" +max_gas = 0 +max_steps = 100000 +ignore_tests=[] + +[[suite]] +id = "light" +path="tests/src/GeneralStateTestsFiller/**/*" +max_gas = 500000 +max_steps = 1000 +allow_tests=[ + "add_d0(add_neg1_neg1)_g0_v0", + "mul_d0(mul_2_3)_g0_v0", + "sub_d0(sub_23_1)_g0_v0", + "div_d0(div_2_big)_g0_v0", + "sdiv_d0(sdiv_1_neg1)_g0_v0", + "mod_d0(mod_2_3)_g0_v0", + "smod_d0(smod_2_3)_g0_v0", + "addmod_d0(addmod_1_2_2)_g0_v0", + "mulmod_d0(mm_1_2_2)_g0_v0", + "exp_d7(exp_2_257)_g0_v0", + "signextend_d0(invalid_byte)_g0_v0", + "lt_d0(lt_neg2_0)_g0_v0", + "gt_d0(gt_neg2_0)_g0_v0", + "slt_d0(slt_neg2_0)_g0_v0", + "sgt_d0(sgt_neg2_0)_g0_v0", + "eq_d0(eq_neg5_neg3)_g0_v0", + "iszero_d0(iszero_neg1)_g0_v0", + "and_d0(and_2_2)_g0_v0", + "or_d0(or_2_2)_g0_v0", + "xor_d0(xor_2_2)_g0_v0", + "not_d0_g0_v0", + "byte_d0(byte_31_big)_g0_v0", + "shl_-1_0_d0_g0_v0", + "shr_-1_0_d0_g0_v0", + # SAR + # KECCAK + # ADDRESS + # BALANCE + "envInfo_d8(origin)_g0_v0", + "envInfo_d4(caller)_g0_v0", + "envInfo_d5(callvalue)_g0_v0", + "calldataload_d0(two_bytes)_g0_v0", + "envInfo_d9(calldatasize)_g0_v0", + "calldatacopy_d7(sec)_g0_v0", + "envInfo_d6(codesize)_g0_v0", + "envInfo_d1(codecopy)_g0_v0", + "envInfo_d7(gasprice)_g0_v0", + # EXTCODESIZE + # EXTCODECOPY + # RETURNCODESIZE + # RETURNCODECOPY + # EXTCODEHASH (need to find a test for it) + "blockInfo_d0(coinbase)_g0_v0", + "blockInfo_d4(timestamp)_g0_v0", + "blockInfo_d3(number)_g0_v0", + "blockInfo_d1(difficulty)_g0_v0", + "blockInfo_d2(gaslimit)_g0_v0", + "chainId_d0_g0_v0", + "selfBalance_d0_g0_v0", + # no tests for BASEFEE ? + "refundMax_d0_g0_v0", # POP + "mload16bitBound_d0_g0_v0", + "gasCostMemory_d44_g0_v0", # MSTORE + "randomStatetest148_d0_g0_v0", # MSTORE8 + "SLOAD_Bounds_d0_g0_v0", + "sstoreGas_d0_g0_v0", + "JUMP_Bounds2_d0_g0_v0", + "JUMPI_Bounds_d0_g0_v0", + "callcode_checkPC_d0_g0_v0", # PC + "randomStatetest310_d0_g0_v0", # MSIZE + "RawCallGas_d0_g0_v0", + # JUMPDEST + "push_d0(push1)_g0_v0", + "push_d1(push2)_g0_v0", + "push_d2(push3)_g0_v0", + "push_d3(push4)_g0_v0", + "push_d4(push5)_g0_v0", + "push_d5(push6)_g0_v0", + "push_d6(push7)_g0_v0", + "push_d7(push8)_g0_v0", + "push_d8(push9)_g0_v0", + "push_d9(push10)_g0_v0", + "push_d10(push11)_g0_v0", + "push_d11(push12)_g0_v0", + "push_d12(push13)_g0_v0", + "push_d13(push14)_g0_v0", + "push_d14(push15)_g0_v0", + "push_d15(push16)_g0_v0", + "push_d16(push17)_g0_v0", + "push_d17(push18)_g0_v0", + "push_d18(push19)_g0_v0", + "push_d19(push20)_g0_v0", + "push_d20(push21)_g0_v0", + "push_d21(push22)_g0_v0", + "push_d22(push23)_g0_v0", + "push_d23(push24)_g0_v0", + "push_d24(push25)_g0_v0", + "push_d25(push26)_g0_v0", + "push_d26(push27)_g0_v0", + "push_d27(push28)_g0_v0", + "push_d28(push29)_g0_v0", + "push_d29(push30)_g0_v0", + "push_d30(push31)_g0_v0", + "push_d31(push32)_g0_v0", + "dup_d0(dup1)_g0_v0", + "dup_d1(dup2)_g0_v0", + "dup_d2(dup3)_g0_v0", + "dup_d3(dup4)_g0_v0", + "dup_d4(dup5)_g0_v0", + "dup_d5(dup6)_g0_v0", + "dup_d6(dup7)_g0_v0", + "dup_d7(dup8)_g0_v0", + "dup_d8(dup9)_g0_v0", + "dup_d9(dup10)_g0_v0", + "dup_d10(dup11)_g0_v0", + "dup_d11(dup12)_g0_v0", + "dup_d12(dup13)_g0_v0", + "dup_d13(dup14)_g0_v0", + "dup_d14(dup15)_g0_v0", + "dup_d15(dup16)_g0_v0", + "swap_d0(swap1)_g0_v0", + "swap_d1(swap2)_g0_v0", + "swap_d2(swap3)_g0_v0", + "swap_d3(swap4)_g0_v0", + "swap_d4(swap5)_g0_v0", + "swap_d5(swap6)_g0_v0", + "swap_d6(swap7)_g0_v0", + "swap_d7(swap8)_g0_v0", + "swap_d8(swap9)_g0_v0", + "swap_d9(swap10)_g0_v0", + "swap_d10(swap11)_g0_v0", + "swap_d11(swap12)_g0_v0", + "swap_d12(swap13)_g0_v0", + "swap_d13(swap14)_g0_v0", + "swap_d14(swap15)_g0_v0", + "swap_d15(swap16)_g0_v0", + "log0_emptyMem_d0_g0_v0", + "log1_emptyMem_d0_g0_v0", + "log2_emptyMem_d0_g0_v0", + "log3_emptyMem_d0_g0_v0", + "log4_emptyMem_d0_g0_v0", + # CREATE + "callcode_checkPC_d0_g0_v0", # for CALL + # CALLCODE + # RETURN + # DELEGATECALL + # CREATE2 + # STATICCALL + # REVERT -unimplemented_opcodes = [ - "EXP", - "SAR", - "RETURN", - "REVERT", - "SHA3", - "ADDRESS", - "BALANCE", - "EXTCODESIZE", - "EXTCODECOPY", - "RETURNDATASIZE", - "RETURNDATACOPY", - "CREATE", - "CREATE2", - "CALLCODE", - "DELEGATECALL", - "STATICCALL", - "SELFDESTRUCT" -] - -# ignored tests, must fix --------------------------------------------------------------- - -[[ignore_test]] -desc = "***panicked at 'circuit should pass', contraint error" -ids=["random_d3(random3)_g0_v0","random_d4(random4)_g0_v0"] - -[[ignore_test]] -desc = "***incorrect rw witness." -ids = ["invalidAddr_d31(ok)_g0_v0"] - -[[ignore_test]] -desc = "gen_associated_ops memory check error" -ids = [ - "callDataCopyOffset_d0_g0_v0", - "calldatacopy_dejavu2_d0_g0_v0", - "codeCopyOffset_d0_g0_v0", - "bufferSrcOffset_d10(ok)_g0_v0", - "bufferSrcOffset_d12(ok)_g0_v0", - "bufferSrcOffset_d13(ok)_g0_v0", - "bufferSrcOffset_d14(ok)_g0_v0", - "bufferSrcOffset_d2(ok)_g0_v0", - "bufferSrcOffset_d20(ok)_g0_v0", - "bufferSrcOffset_d21(ok)_g0_v0", - "bufferSrcOffset_d22(ok)_g0_v0", - "bufferSrcOffset_d23(ok)_g0_v0", - "bufferSrcOffset_d26(ok)_g0_v0", - "bufferSrcOffset_d30(ok)_g0_v0", - "bufferSrcOffset_d34(ok)_g0_v0", - "bufferSrcOffset_d36(ok)_g0_v0", - "bufferSrcOffset_d37(ok)_g0_v0", - "bufferSrcOffset_d38(ok)_g0_v0", - "bufferSrcOffset_d44(ok)_g0_v0", - "bufferSrcOffset_d45(ok)_g0_v0", - "bufferSrcOffset_d46(ok)_g0_v0", - "bufferSrcOffset_d47(ok)_g0_v0", - "bufferSrcOffset_d6(ok)_g0_v0" -] - -[[ignore_test]] -desc = "NotEnoughRowsAvailable { current_k: 12 }" -ids = [ - "oog_d2(success)_g0_v0", - "oog_d4(success)_g0_v0", - "push32withoutByte_d0_g0_v0" -] - -[[ignore_test]] -desc = "a an inexistent contract at address is called, but parse_call() (or alike) does not support it yet" -ids = [ - "invalidAddr_d41(ok)_g0_v0", - "underflowTest_d91(CALL-7)_g0_v0", - "CallToNameRegistratorAddressTooBigRight_d0_g0_v0", - "ZeroValue_CALL_d0_g0_v0", - "NonZeroValue_CALL_d0_g0_v0", - "randomStatetest138_d0_g0_v0", ] -[[ignore_test]] -desc = "Integer overflow when casting to u64" -ids = ["envInfo_d3(codecopy_neg_offset)_g0_v0", "codecopy_dejavu2_d0_g0_v0","randomStatetest222_d0_g0_v0"] - -[[ignore_test]] -desc = "call with value and not enough value to send" -ids= ["callWithHighValue_d0_g0_v0"] - -[[ignore_test]] -desc = "Fully implement PUSHn #633" -ids = ["randomStatetest0_d0_g0_v0"] +[[set]] +id = "sigkill" +desc = "tests that sigkill" +tests = [] # skipped tests, do not need to be fixed -------------------------------------------------- -[[skip_test]] -desc = "maximum geth trace size (10MB)" -ids = [ - "randomStatetest163_d0_g0_v0", - "randomStatetest150_d0_g0_v0", - "randomStatetest154_d0_g0_v0", - "randomStatetest159_d0_g0_v0", - "randomStatetest36_d0_g0_v0", - "randomStatetest101_d0_g0_v0", - "randomStatetest185_d0_g0_v0", - "randomStatetest326_d0_g0_v0", - "randomStatetest177_d0_g0_v0", - "randomStatetest178_d0_g0_v0", - "randomStatetest263_d0_g0_v0", - "randomStatetest205_d0_g0_v0", - "randomStatetest209_d0_g0_v0", - "randomStatetest306_d0_g0_v0", - "randomStatetest384_d0_g0_v0", - "randomStatetest48_d0_g0_v0", - "MLOAD_Bounds3_d0_g0_v0", - "MLOAD_Bounds3_d0_g1_v0", - "MSTORE_Bounds2a_d0_g1_v0", - "Call1024PreCalls_d0_g2_v0", - "Call1024PreCalls_d0_g1_v0", - "msize_d5(farChunk)_g0_v0", - "CallcodeToPrecompileFromTransaction_d0_g0_v0", - "CallcodeToPrecompileFromCalledContract_d0_g0_v0", - "CallcodeToPrecompileFromContractInitialization_d0_g0_v0", - "Call1024PreCalls_d0_g1_v0", - "Call1024PreCalls_d0_g0_v0", - "static_Call1024PreCalls2_d0_g0_v0", - "shiftSignedCombinations_d0_g0_v0", - "CreateOOGafterMaxCodesize_d5(HighContractCount_DelegateCreate_CallCreate_SelfDestruct)_g0_v0", - "CallInfiniteLoop_d0_g0_v0", - "static_callCreate2_d2_g0_v0", - "static_CallIdentity_5_d0_g0_v0", - "static_CallSha256_5_d0_g0_v0", - "static_CallRipemd160_5_d0_g0_v0", - "static_callChangeRevert_d1_g0_v0", - "static_callcallcodecall_010_OOGE_d0_g0_v0", - "static_callcallcall_000_OOGMBefore_d0_g0_v0", - "static_callcallcodecall_010_OOGMBefore_d1_g0_v0", - "static_callcallcodecall_010_OOGMBefore2_d0_g0_v0", - "static_callcallcallcode_001_OOGMBefore2_d1_g0_v0", - "static_callcallcallcode_001_OOGMBefore_d0_g0_v0", - "static_Call10_d1_g0_v0", - "static_Call10_d0_g0_v0", - "jsonCall10_d0_g0_v0", - "block504980_d0_g0_v0", - "shiftCombinations_d0_g0_v0", - "static_LoopCallsThenRevert_d0_g1_v0", - "CallRecursiveMethods_d0_g0_v0", - "static_LoopCallsThenRevert_d0_g0_v0", - "static_callcallcodecall_010_OOGMAfter_d1_g0_v0", - "static_callcallcodecall_010_OOGMAfter_2_d1_g0_v0", - "static_callcallcallcode_001_OOGMAfter2_d1_g0_v0", - "static_callcallcallcode_001_OOGMAfter_3_d1_g0_v0", - "static_callcallcodecall_010_OOGMAfter_3_d1_g0_v0", - "static_callcodecallcall_100_OOGMAfter2_d0_g0_v0", - "static_callcallcallcode_001_OOGMAfter_d1_g0_v0", - "static_callcodecallcall_100_OOGMAfter_2_d0_g0_v0", - "static_callcodecallcall_100_OOGMAfter2_d0_g0_v1", - "ContractCreationSpam_d0_g0_v0", - "CreateOOGafterMaxCodesize_d4(HighContractCount_DelegateCreate_CallCreateOOG)_g0_v0", - "static_callcallcall_000_OOGMAfter2_d0_g0_v0", - "static_callcodecallcallcode_101_OOGMAfter_1_d0_g0_v0", - "createInitFailStackSizeLargerThan1024_d0_g0_v0", - "costRevert_d27(stackOver)_g0_v0", - "costRevert_d20(stackOver)_g0_v0", - "costRevert_d13(stackOver)_g0_v0", - "costRevert_d6(stackOver)_g0_v0", - "static_Call1MB1024Calldepth_d1_g0_v0", - "stateRevert_d6(stackOver)_g0_v0", - "DelegatecallToPrecompileFromTransaction_d0_g0_v0", - "DelegatecallToPrecompileFromCalledContract_d0_g0_v0", - "DelegatecallToPrecompileFromContractInitialization_d0_g0_v0", - "CallWithZeroValueToPrecompileFromTransaction_d0_g0_v0", - "CallWithZeroValueToPrecompileFromCalledContract_d0_g0_v0", - "CallWithZeroValueToPrecompileFromContractInitialization_d0_g0_v0", - "CreateOOGafterMaxCodesize_d3(HighContractCount_NoDelegateCreate_CallCreateOOG)_g0_v0", - "twoOps_d0_g0_v0", - "Call10_d0_g0_v0" -] +[[skip_tests]] +desc = "" +tests = [] # ignored paths ------------------------------------------------------------------------- -[[skip_path]] +[[skip_paths]] desc = "unimplemented" paths = [ "EIP1559", "EIP2930", "stPreCompiledContracts", - "stZeroKnowledge" + "stZeroKnowledge" ] -[[skip_path]] +[[skip_paths]] desc = "too big" paths = [ "stTimeConsuming", @@ -196,7 +191,7 @@ paths = [ "50000" ] -[[skip_path]] +[[skip_paths]] desc = "defines asm" paths = [ "stackLimitGas_1023Filler.json", @@ -215,7 +210,7 @@ paths = [ "chainIdGasCostFiller.json" ] -[[skip_path]] +[[skip_paths]] desc = "bad json" paths = [ "Opcodes_TransactionInitFiller", @@ -229,7 +224,7 @@ paths = [ "ValueOverflowFiller" # weird 0x:biginteger 0x... ] -[[skip_path]] +[[skip_paths]] desc = "uses :solidity" paths = [ "RevertRemoteSubCallStorageOOGFiller.yml", diff --git a/testool/README.md b/testool/README.md new file mode 100644 index 0000000000..f8f84a32b0 --- /dev/null +++ b/testool/README.md @@ -0,0 +1,114 @@ +# Testool + +The `testool` is a binary cli that focus on provide tools for testing. + +To use it, just compile with `cargo build --release` and run `../target/release/testool`. + +This tool at this moment has 2 main functionalities: run raw bytecode and run ethereum tests. + +## Run oneliner spec + +The oneliner spec is invoked by using `--oneliner` parameter + +The spec has the following form + +`txparams` `account 1` `account 2` ... `account n` + +where + +- `txparams` have the form `call|create`;`calldata`;`value`;`gas` + - if `create`is specified the `to` field in the tx is left blank, is not the first account specified is used as the contract to call + - `calldata`,`value` and `gas` are optional +- `account` have the form `address`;`code`;`balance`;`slot 1`:`value 1`;..`slot n`..`value n` + - `address` can be shortened, eg.`10` and `0x10` is expanded to `0x....10` + - `code` is optional, and can be specified in hex or in asm (`PUSH1(1),PUSH1(1),MLOAD`) + - `balance` and `value` are optional + - `slot` and `value` can be specified multiple times + +example + +- `../target/release/testool --oneliner "call 12;60016002"`: call contract `0x...12` that contains the code PUSH1(1) PUSH1(2) +- `../target/release/testool --oneliner "call;;2000 12;PUSH1(0),SLOAD,CALLVALUE,EQ,PUSH1(1),SSTORE;;00:2000"`: call the contract and send 2000 as value, and compare with the stored value (2000) in the slot 0, write into slot 1 + +## Run the ethereum tests + +Run + +``` + ../target/release/testool --suite default +``` +or + +``` + ../target/release/testool --suite nightly +``` + +The "official EVM" ethereum tests are cloned as a gitmodule in `testool/tests`. +We are using the tests located in `testool/tests/src/GeneralStateTestsFiller`, but other locations can be specified, also. + + +### The ethereum tests files + +These tests are written in `json` or `yml`, and, in general it specifies 4 sections: + +- General environment to generate a block (blocknumber, timestamp, gaslimit, etc...) +- Initial account states (with its balance, nonce, storage, and code) +- A set of transactions to be executed from the initial state, each transaction defines one test +- The account states resulting of the execution of these transactions + +You can find (here)[https://ethereum-tests.readthedocs.io/en/latest/test_filler/blockchain_filler.html] the specification for these files in detail. + +Official ethereum tests are maintained by the foundation but you can write your own. + +### Configuration file + +The `Config.toml` configuration defines which files and tests to process. + +#### Defining test suites + +In the config file you define `[[suite]]`s that defines how tests will be executed. + +- `id` is the identifier of the suite. The default suite is called `default`. +- `max_steps` the maximum number of executed opcodes. If this is reached, the test is marked to be ignored. +- `max_gas` the maximum gas of a test. If the specified maximum gas is reached, the test is marked to be ignored. Put a `0` if you do not want to limit it. +- you should define also only one of these parameters: + - `allow_tests` with the list of tests or test sets to execute. All others will be excluded. Test sets should be prefixed with `&` + - `ignore_tests` with the list of test or test sets to ignore. All others will be included. Test sets should be prefixed with `&` + +#### Test sets + +Test sets are created by using the `[[set]]` section and should define +- `id` the identification of the set (without any `&`). Note that ids can be duplicated, this means that are tests with the same id are joined together when used. +- `desc` a description of the test set +- `tests` a list of tests + +#### Skipping the execution of problematic tests + +Sometimes there are some files or specific tests that we want to disable at all. Those are defined with: + +- `[[skip_test]]` defines a set of tests that are always ignored. +- `[[skip_path]]` defined a set of files/folders that are always ignored. This is useful since sometimes there are some tests with weird encodings. + +### Generating reports + +When the command line parameter `--report` is defined, it automatically: + +- After the execution, a two files are created in the `report` folder. They are + - `-.hml` with the browseable results of the execution. + - `-.csv` with the raw results of the execution +- The HTML file also contains the diff with the previous result. The previous result file is the more recent csv file with different commit from the current one + +Sometimes do you want to only re-execute tests that are marked as `Ignored` (because you are implementing something new). In this case, you can specify `--cache <>.csv` to use the previous results. + +NOTE: if you do not execute with `--report` the tool will exit the process with `1` if there is any test that is not working. + + +### Manually executing the tests + +Usually we have to debug and run the tests manually to check if everything works ok. We provide a set of command line parameters to help with this. + +- `testool [--suite xxx] --cache ` to execute all tests, and by default skipping Ignored tests in cache, and keeping the results (cache) CSV file. If you delete entries from the cache file, and re-run the tool again, only the deleted tests will be executed again + +- `testool [--suite xxx] --cache --levels fail,panic` to execute all tests but skipping the tests in cache which status (i.g. result level) is NOT Fail or Panic. Notice levels is case insensitive. + +- `testool [--suite xxx] --inspect ` only executed the selected test (even if cached, or ignored). Use `RUST_BACKTRACE=1` here to check if anything fails. Also gives a dump of the test as also to the geth steps executed. diff --git a/testool/codehash.txt b/testool/codehash.txt index 9f6a2c54b7..233a3ad2d3 100644 --- a/testool/codehash.txt +++ b/testool/codehash.txt @@ -189,7 +189,7 @@ a6b511ce812a179b7a64838fbaa1d07cf7cd4b36c8060e086aa4b5fa61c971fd=600060006000600 f622260e13d7fabcc2cd9c1354d70e72614d8880f0c9682d07628c29b908e463=61600d600055630fffffff5600 d038887431975103a6ff47e75a1d183785b52fe006a23f264fc2eb621cff5b2f=600051506001600003506000515661600d60005500 3910e9d2cbc043a8ba787db1c0a21eb65944c7da49fc5485bdc90856d36e9c81=60006000600060006004356101000162010000f400 -a18f72995cc53877315840eb65f7906e0c90fddf4d49711297129d5539ce03de=600435600080600080846113885a03f45050 +a18f72995cc53877315840eb65f7906e0c90fddf4d49711297129d5539ce03de=6004356000600060006000846113885a03f45050 6648e38b61baede61a47f6b6fdd734b8dae0b2fd565c4b13caad748d3c77aa61=61600d60005560006010602002575b00 dfddcfaa0f3d8f89349db1aaa2ab93a46d95d27f80f9c11bfa55d98d52a9ef39=61600d60005560ff630fffffff5700 5f897f8795f7aaecc09acc9d1248777be536bed19a84da9fed831cfc1741b597=61600d6000556000630fffffff5700 @@ -384,1133 +384,872 @@ ecc2da6d921e3a8add8be7f8e2edb8affa9362a00081d0fa10c3fcb93ad50390=73095e7baea6a6c 0f8768e84bd90b2a15fa1d47b16a20496ce88b55f6e2c461a38dcbb3aff56653=63deadbeef6000526101206000f300 529602fa473129c61090597d1c9cdc954defa61394356c24412d9b65df7591cf=600035ff00 9ee82de581ce9d8b59a47c812ff01adfff66aca971f144109aa5ec74b42d9a50=60016024351461001157600050610019565b61c0de612000525b60026024351461002b57600050610032565b6002612000525b6000604435146100445760005061004d565b61200051612040525b60016044351461005f57600050610071565b60a060020a6001026120005101612040525b60026044351461008357600050610095565b60fe60020a6001026120005101612040525b6003604435146100a7576000506100b9565b60ff60020a6001026120005101612040525b6004604435146100cb576000506100dd565b60a060020a6001026120005103612040525b67ff00ff00ff00ff006120205266ff00ff00ff00ff6120605260316004351461010857600050610139565b61200051316120205261204051316120605260016024351461012f57600061208052610138565b62010000612080525b5b603b6004351461014b5760005061017a565b612000513b61202052612040513b6120605260016024351461017257600061208052610179565b600f612080525b5b603c6004351461018c576000506101e0565b60206000612020612000513c60206000612060612040513c6001602435146101b9576000612080526101df565b7f63deadbeef6000526101206000f3000000000000000000000000000000000000612080525b5b603f600435146101f257600050610240565b612000513f61202052612040513f612060526001602435146102195760006120805261023f565b7f85ab232a015279867a1f5b5da4f9688c6c92e555c122e9147f9d13bc53c03e92612080525b5b60f160043514610252576000506102bb565b60206120206020612000600061200051611000f15060206120606020612000600061204051611000f1506001602435146102b0577f9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2612080526102ba565b63deadbeef612080525b5b60f2600435146102cd57600050610336565b60206120206020612000600061200051611000f25060206120606020612000600061204051611000f25060016024351461032b577f9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed261208052610335565b63deadbeef612080525b5b60f460043514610348576000506103ad565b6020612020602061200061200051611000f4506020612060602061200061204051611000f4506001602435146103a2577f9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed2612080526103ac565b63deadbeef612080525b5b60fa600435146103bf57600050610424565b6020612020602061200061200051611000fa506020612060602061200061204051611000fa50600160243514610419577f9267d3dbed802941483f1afa2a6bc68de5f653128aca9bf1461c5d0a3ad36ed261208052610423565b63deadbeef612080525b5b60ff60043514610436576000506104b6565b61200051316120a052600060006020612000600062dead016310000000f150612000513161202052600060006020612040600062dead026310000000f150612000513161206052612020516120605103612060526120a0516120205103612020526001602435146104ad57611000612080526104b5565b611000612080525b5b61206051612020510360005561208051612020510360015560006101005500 -0e9c2dc682cf70a4bc15c56c064427939e0131445e20b4404363021ae9652610=fe -9a270b7cc69db5ebae71e25c626f1c262f9d6de5dc420a84bc7c80873af0984e=fe -2b43e66f7532c69d2c7c3bea96fd2de05c1d839322d155e3a537376d7e4c97e0=6220c0de803b80600080843c806000f3 -29e7cb59911b8f832e89bec6d412a599527b814628d898f6bdd863ff80e35f63=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f1811461015d5760f281146101715760f481146101855760fa81146101985761f1f181146101ab5761f2f181146101c15761f4f181146101d75761faf181146101ec5761f1f281146102015761f2f281146102175761f4f2811461022d5761faf281146102425761f1f481146102575761f2f4811461026d5761f4f481146102835761faf481146102985761f1fa81146102ad5761f2fa81146102c35761f4fa81146102d95761fafa81146102ee5760fd81146103035760fe81146103055760ff81146103075760f081146103095760f5811461032c5761f0f181146103525761f5f1811461037c5761f0f281146103a95761f5f281146103cc5761f0f481146103f25761f5f481146104145761f0fa81146104395761f5fa8114610462576460baccfa57811461048e5765bad0bad0bad06000526104a8565bfe5b602060008060008061ca115af195506104a8565b602060008060008061ca115af295506104a8565b6020600080600061ca115af495506104a8565b6020600080600061ca115afa95506104a8565b602060008060008063ca1100f15af195506104a8565b602060008060008063ca1100f15af295506104a8565b6020600080600063ca1100f15af495506104a8565b6020600080600063ca1100f15afa95506104a8565b602060008060008063ca1100f25af195506104a8565b602060008060008063ca1100f25af295506104a8565b6020600080600063ca1100f25af495506104a8565b6020600080600063ca1100f25afa95506104a8565b602060008060008063ca1100f45af195506104a8565b602060008060008063ca1100f45af295506104a8565b6020600080600063ca1100f45af495506104a8565b6020600080600063ca1100f45afa95506104a8565b602060008060008063ca1100fa5af195506104a8565b602060008060008063ca1100fa5af295506104a8565b6020600080600063ca1100fa5af495506104a8565b6020600080600063ca1100fa5afa95506104a8565bfe5bfe5bfe5b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6104a8565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6104a8565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506104a8565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506104a8565b8160008563c0dec0de3c81846000f094506020600080600080895af295506104a8565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506104a8565b8160008563c0dec0de3c81846000f0945060206000806000885af495506104a8565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506104a8565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506104a8565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506104a8565b6103ff6000526020600060206000806460baccfa575af195505b50846104b45760206000fd5b836104bf5760206000fd5b600051600055505050505050 -8362f328002b4d0c08e880edbc2133df809f450ed36f03185a99060b9498af41=fe -dfb3a38ca43d43a65edc3c3a0fd72cd14caac2ddc137b69acbb056f64a00aa13=602060008060008061ca115af160155760206000fd5b60206000f3 -fdcfd31543389df1a8b8bec4d90fd0ddcc4a817a631932e94529b11d53f8df17=602060008060008061ca115af260155760206000fd5b60206000f3 -65699b2d0e8558090352144d9310209295295547704451860855f4c230ce596e=6020600080600061ca115af460145760206000fd5b60206000f3 -e43e9d52cbc260ffe419a5c93a18852abe333e1bf102711765f13090f29793a2=6020600080600061ca115afa60145760206000fd5b60206000f3 -cbf22222a7bb92f681e16384d575b92e73420196573a32d298ba4475923e9e98=fe -0514a02fa4c5841a8341bd250fe42c5a340ea8830ded807baab6b37492d02139=fe +0e9c2dc682cf70a4bc15c56c064427939e0131445e20b4404363021ae9652610=fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 +9a270b7cc69db5ebae71e25c626f1c262f9d6de5dc420a84bc7c80873af0984e=fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 +2b43e66f7532c69d2c7c3bea96fd2de05c1d839322d155e3a537376d7e4c97e0=6220c0de803b8060006000843c806000f35050 +29e7cb59911b8f832e89bec6d412a599527b814628d898f6bdd863ff80e35f63=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101865760f2811461019c5760f481146101b25760fa81146101c65761f1f181146101da5761f2f181146101f25761f4f1811461020a5761faf181146102205761f1f281146102365761f2f2811461024e5761f4f281146102665761faf2811461027c5761f1f481146102925761f2f481146102aa5761f4f481146102c25761faf481146102d85761f1fa81146102ee5761f2fa81146103065761f4fa811461031e5761fafa81146103345760fd811461034a5760fe81146103c75760ff81146104465760f081146104c45760f581146104e75761f0f1811461050d5761f5f181146105395761f0f281146105685761f5f2811461058d5761f0f481146105b55761f5f481146105d85761f0fa81146105fe5761f5fa8114610628576460baccfa5781146106555765bad0bad0bad0600052610670565bfe7fdead60a700000000000000000000000000000000000000000000000000000000600052610670565b6020600060006000600061ca115af19550610670565b6020600060006000600061ca115af29550610670565b602060006000600061ca115af49550610670565b602060006000600061ca115afa9550610670565b6020600060006000600063ca1100f15af19550610670565b6020600060006000600063ca1100f15af29550610670565b602060006000600063ca1100f15af49550610670565b602060006000600063ca1100f15afa9550610670565b6020600060006000600063ca1100f25af19550610670565b6020600060006000600063ca1100f25af29550610670565b602060006000600063ca1100f25af49550610670565b602060006000600063ca1100f25afa9550610670565b6020600060006000600063ca1100f45af19550610670565b6020600060006000600063ca1100f45af29550610670565b602060006000600063ca1100f45af49550610670565b602060006000600063ca1100f45afa9550610670565b6020600060006000600063ca1100fa5af19550610670565b6020600060006000600063ca1100fa5af29550610670565b602060006000600063ca1100fa5af49550610670565b602060006000600063ca1100fa5afa9550610670565bfe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103c257640badbadbad6000525b610670565bfe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561044157640badbadbad6000525b610670565bfe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156104bf57640badbadbad6000525b610670565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c610670565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c610670565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af19550610670565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af19550610670565b8160008563c0dec0de3c81846000f0945060206000600060006000895af29550610670565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af29550610670565b8160008563c0dec0de3c81846000f094506020600060006000885af49550610670565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af49550610670565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa9550610670565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa9550610670565b6103ff600052602060006020600060006460baccfa575af195505b5084151561067e5760206000fd5b83151561068b5760206000fd5b600051600055505050505050 +8362f328002b4d0c08e880edbc2133df809f450ed36f03185a99060b9498af41=fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 +dfb3a38ca43d43a65edc3c3a0fd72cd14caac2ddc137b69acbb056f64a00aa13=6020600060006000600061ca115af1151560195760206000fd5b60206000f3 +fdcfd31543389df1a8b8bec4d90fd0ddcc4a817a631932e94529b11d53f8df17=6020600060006000600061ca115af2151560195760206000fd5b60206000f3 +65699b2d0e8558090352144d9310209295295547704451860855f4c230ce596e=602060006000600061ca115af4151560175760206000fd5b60206000f3 +e43e9d52cbc260ffe419a5c93a18852abe333e1bf102711765f13090f29793a2=602060006000600061ca115afa151560175760206000fd5b60206000f3 +cbf22222a7bb92f681e16384d575b92e73420196573a32d298ba4475923e9e98=fe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe +0514a02fa4c5841a8341bd250fe42c5a340ea8830ded807baab6b37492d02139=fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd 38f547750047a472fa72fec253a4527ebd73e74d1ef59d71ab51dff7714d7005=6000ff -20eab3c8d300ca0bc99f12bab2359d3afe554d389def84f35d804da88303ecbd=60003560008103600b57fe5b600181036000526020600060206000806460baccfa575af1602c5760206000fd5b60206000f3 -42f7c2f75c75cef03d21d28ea88ee056455a41df4fa69e84448ada32ee1e20cc=610200600080f050 -5049b9ef30dce1c4fc833042e5e868e76b8447d2a38c364ac574f3e5b8e94564=5a615a1701610200600080f550 +20eab3c8d300ca0bc99f12bab2359d3afe554d389def84f35d804da88303ecbd=6000356000811415603557fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af1151560595760206000fd5b60206000f350 +42f7c2f75c75cef03d21d28ea88ee056455a41df4fa69e84448ada32ee1e20cc=61020060006000f050 +5049b9ef30dce1c4fc833042e5e868e76b8447d2a38c364ac574f3e5b8e94564=5a615a170161020060006000f550 9a76f62b8b1305059c0392f4d8293bc5d6f13ff4a3502f35a56ffea9f3102e91=00 -c71639a1d42dc0079620a8748605a805df5009b435adcef233671749fcd6fea8=610100600061010060008061ca115af150 -cf2810c927b9404e13cfd3755b60e6da83a777019e9290ba13bc2ef72028c384=610100600061010060008061ca115af250 +c71639a1d42dc0079620a8748605a805df5009b435adcef233671749fcd6fea8=61010060006101006000600061ca115af150 +cf2810c927b9404e13cfd3755b60e6da83a777019e9290ba13bc2ef72028c384=61010060006101006000600061ca115af250 7965d59aacd6cb567c346703fe84168ca1247909772f914c9481348eecab24c3=6101006000610100600061ca115af450 caead2353c6dfe042005dcced75ef872d4485c09b0a608a0142f7e6617963e5f=6101006000610100600061ca115afa50 635416a136a2c77e605894a10cbb3034338efdc3261571136d4b5689c377b7a2=61b0005150 d5fa7be3053a269955f2681e3456d906ed87394a2a8493c729b3582b438c12b5=60ff61b00052 a340c6e10bcd05d0f73c7b697a98ed582f2244cb0c37315ec4743247e51c173b=60ff61b00053 0f86028bf04f9934739e785ea0362e83beb4eb2bf7e941deb606dcc2f571e38f=61beef60002050 -4c10255b7e0067acc2ebd06666664cbb0e06b57f5e2da8d7f9065c8b6dd44904=61ca11803b600080833c50 -430d28ac555e5377b78dcc35ef76ea915c1f1830b34cae9638b2b46836a41f9b=600061ea6060043562c0de00015b6001838303111560445760028284010460008060008060008686f1600081036033578194505b60018103603e578193505b5050600d565b81600055505050 +4c10255b7e0067acc2ebd06666664cbb0e06b57f5e2da8d7f9065c8b6dd44904=61ca11803b60006000833c50 +430d28ac555e5377b78dcc35ef76ea915c1f1830b34cae9638b2b46836a41f9b=600061ea6060043562c0de00015b60018383031115604957600282840104600060006000600060008686f160008114156036578194505b60018114156042578193505b50505b600d565b81600055505050 938ee3f4c10a7ca8880a8893537cad1a5c5be41c18cf679b56d84ff0a7c86ba9=6009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 230ad8b2bee2664f3917e0eaa4fb99565b9b2989a0f5cd7847a2fcdc576b7e69=6009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0c178b5973abc40e8a8e1e36c759cfbbcea1c5272ee5efafef30b2f4b258caa3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260010c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260010c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0c178b5973abc40e8a8e1e36c759cfbbcea1c5272ee5efafef30b2f4b258caa3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260010c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260010c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 44988850b8a12a167c5cd7dddcd014166d37ab13ebe839fad024b62de3e660cf=6009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 96475191b3bcb0ad37a3b6df38be56139deaec7e02f1487bad194953eca95d21=6009600860076006600560046003600260010c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe cb7adbe8f8ee805ca68468f69f10f910b3853a98df2bdf577927b75fb11285e7=6009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -e3e1455165b47b69c29d61a2bc5078d5ad4d65e92b9687cb7180a3574e37c24f=600035600081036046576009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +e3e1455165b47b69c29d61a2bc5078d5ad4d65e92b9687cb7180a3574e37c24f=60003560008114156047576009600860076006600560046003600260010c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 17685510e75e3f74b8218b94229451ec1cc228ca37654b9b4634355eae2dbf9c=6009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 23951503023e580b1117ac0898cfba8b28e874ff8ecbb10741a11fc490966c44=6009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d5f2777b29693306828cec239d9c18c0712efd524dc6f747104d87feb3448b21=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260010d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260010d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d5f2777b29693306828cec239d9c18c0712efd524dc6f747104d87feb3448b21=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260010d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260010d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 62a6f08909838c6f7fd571901020f12c41c6915b77466aa87049392d55708787=6009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 8225f662322132ba756ddf40b9d38ee77569900e50f6017356c85ecefda4f0a4=6009600860076006600560046003600260010d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe ab0505ea2db66ed1dcae4b3ca8c86eb81a6cd7263bc4dbd23019560079f9a2f9=6009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -1de16d5bf91595f686c8a3e0b6759cd058cc82e743b0ad4b43bd5aa97b767c88=600035600081036046576009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +1de16d5bf91595f686c8a3e0b6759cd058cc82e743b0ad4b43bd5aa97b767c88=60003560008114156047576009600860076006600560046003600260010d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1068a1249d4c3b6b6f83ec022b0b09aba43bbc01520e2c6b2b42a546625fa486=6009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 d92166b2a2f6ab44b2fc9f7c8e177c7a20b78ac7d0f1f7ca688883cb378c4c64=6009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -8eda3038d723b0f5c25b04f2fce101c2316df4c50ba5bd7741e70a044348f7be=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260010e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260010e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +8eda3038d723b0f5c25b04f2fce101c2316df4c50ba5bd7741e70a044348f7be=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260010e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260010e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 253155f71a6ed583e6b384069ad9fb1b6702e97a8b32df4b87224ca37c84f685=6009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b411b634893a0d8a4d864f6dc3fd63bf69d2094b74608861b86f17f3dc63a3d1=6009600860076006600560046003600260010e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 2af31abacbbeaaf462fe2936c4b2d05649426985fe42b4061019a912a0f797d8=6009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -6a0bd10d9b4b130170f5ddb04a7738b14aabe4c805af9235f51f5ec4267dd2cf=600035600081036046576009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +6a0bd10d9b4b130170f5ddb04a7738b14aabe4c805af9235f51f5ec4267dd2cf=60003560008114156047576009600860076006600560046003600260010e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 c907e58ddf59dde5cda116a73a3be28226593da0b0278cd5b7d675f646493eb9=6009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 139fa7c0b243adb5fd1ca31d3af7d2bee20772d5b2a603a763879b4c984c6084=6009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ee2b3952f8672b7367b2b1ed5b47135309c31ee656bc48b11259d3b5828e9f2e=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260010f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260010f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ee2b3952f8672b7367b2b1ed5b47135309c31ee656bc48b11259d3b5828e9f2e=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260010f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260010f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8fa57f0ab296fa45e253f78c45e7d71aae05d2959f1585a24cab0343397dc611=6009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 41e71afd58b254195323c77a3cf0c3025936553d7ebe1db40db2a235ae09e4d7=6009600860076006600560046003600260010f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 0ef59d8bebe83d676f9e04d12156ade7dca0289de969382f170e878c7ffa2a97=6009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -400fbe7e32c200832d7596b58ff78cbceaa998d7565891132f8718e82241f39b=600035600081036046576009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +400fbe7e32c200832d7596b58ff78cbceaa998d7565891132f8718e82241f39b=60003560008114156047576009600860076006600560046003600260010f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1cc9592eb090e413d93224c9c40e9f0ec4bdcbdcd87c909ffeb7e78469478ed1=6009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 30b094e2b26a74f73b5f9999c6334032fb40d213ac1a42e974305ee36fc3484f=6009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b2854feb50f32aaccfa575fb4860ccde6ff989d0ba1ebf559dcb47bd9a5bc0cd=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260011e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260011e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b2854feb50f32aaccfa575fb4860ccde6ff989d0ba1ebf559dcb47bd9a5bc0cd=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260011e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260011e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 568e661d7df1612a19ba92b59655ad16d37b5f892806110e9206106842850d29=6009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 343f9e016b3d1873b1eeab5bac585e76ecb5458c3e6329d9e78729b1a5e8239d=6009600860076006600560046003600260011e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c51830e3c8437a8e0fb86ae9650a05a5ed4806ad8ce7b6426fafefbfd638e618=6009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -da1e4c58298849b0870a90846bf251ee62076a1c96e882d90550d62c2cee6af5=600035600081036046576009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +da1e4c58298849b0870a90846bf251ee62076a1c96e882d90550d62c2cee6af5=60003560008114156047576009600860076006600560046003600260011e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 58200d9da216bae346a002e950da89f7c8f583330942315f4d033697e0eaf389=6009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 1160b9999f89fdb04e0c310ab5417e25b4a50326a37ce3d6669753c72a749164=6009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -983e12fd64a4c75ea68b3dd69813ee55ffa87f5d8d9e597d2d10572f9596c334=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260011f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260011f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +983e12fd64a4c75ea68b3dd69813ee55ffa87f5d8d9e597d2d10572f9596c334=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260011f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260011f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 b5e02815891113e58d0a6f40c1c09cfd3e2af3ed8ac1c2e14b6cd3b0ab98a6ae=6009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 44a28f59bab3e9db86d9f1a2039c2344dd275c39a183817bbb9b342963fc8853=6009600860076006600560046003600260011f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 389b491a506152871ab588c30fc27545526d502942ebf1f76b808d2ac84fc079=6009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -fb321121abdcb461309886fd0c9afa0bb484a27abd369aa6cc6131fe7fe51677=600035600081036046576009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +fb321121abdcb461309886fd0c9afa0bb484a27abd369aa6cc6131fe7fe51677=60003560008114156047576009600860076006600560046003600260011f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 82671344199c33734491b4e2824df44f9ed75b0feb1246d4507f12e59a297f0d=600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 b521eb06a22eb8bc3373ea257eaa896e1f7aada6b1bd5703706666d3c7270539=600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -59a1a02e81319c8c4fdf78bc0ef07495b2160978b45e0178a72a2ac3ee4aafb3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001217fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001217fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +59a1a02e81319c8c4fdf78bc0ef07495b2160978b45e0178a72a2ac3ee4aafb3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001217fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001217fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 812a84a0e6d3bf51bc645998f0f1c628964001222d7370ddafcefe0a88238afa=600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 1817666e09c78ce0915367cf498574c3ae5f6f5964a18a6c9bbc6794d32bce20=600960086007600660056004600360026001217fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 91dfdcb44d5446d5e14a976bb0b00a7e2082523eae4494a9e57261eec389b6e8=600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -ce6a46d3faa4f776895fc2dff6080147e39e15ce4cbe4d110fd61efd22c3d663=60003560008103604657600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +ce6a46d3faa4f776895fc2dff6080147e39e15ce4cbe4d110fd61efd22c3d663=6000356000811415604757600960086007600660056004600360026001217fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 b777769be0e6d61f5de811b1f25d1421a2cef7a5e848906ff1e5187ff6a99713=600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e8a7f37f57061b04b44539079f0af364057ddf19662e6d0016f44e587315f6db=600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -760ff99e0c688e06674e4afedb6212ecf2b58480a41684749d0137376c2aaa41=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001227fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001227fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +760ff99e0c688e06674e4afedb6212ecf2b58480a41684749d0137376c2aaa41=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001227fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001227fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 ee15e8b1def627c248e0ef2b349e642c28930100a66719b4d9d3b59c32e8d2c6=600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c9ef430aa137465df086e05e6883183d69b4211322ebc5b3dfebc0ad5e60adc6=600960086007600660056004600360026001227fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c12e66e38eb2f29bce1281e9ba5cd1c7b57263a77426e15091292df57bd30ba7=600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8418ea603b4e88c12557e883203943437c425dea592d79c7a1e4f5afb07c7399=60003560008103604657600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8418ea603b4e88c12557e883203943437c425dea592d79c7a1e4f5afb07c7399=6000356000811415604757600960086007600660056004600360026001227fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 3a071d7023fb441bccc3c6aee65e5ce05b2918d1eb4e7ec9b5e2f4dc2c401740=600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 71daa9e7174bf24991b7ce85ea872819e5f50753a06bcb9dca91922054124698=600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -89f20a0e69e5f391e03b60d27e751ee3fb3e46a210b55c1e2c6cc74d2ef3ca89=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001237fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001237fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +89f20a0e69e5f391e03b60d27e751ee3fb3e46a210b55c1e2c6cc74d2ef3ca89=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001237fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001237fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f2331e094cf1086abd868e108d1549172e7bb4dc30d51edba9b262a9060a4761=600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b9b145ac0daaf21ea5e83d3f7e8d0ec148136c453b220834f2cc7002b4bcc343=600960086007600660056004600360026001237fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe b15ddb47eb4585801737e561cc5d2caaa4ad359adf6ce6cb22b4f4e2b331daa7=600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -efbc58adac9e1d333512bcc22be5f575ca088dce0f47710671b465cd85068c7d=60003560008103604657600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +efbc58adac9e1d333512bcc22be5f575ca088dce0f47710671b465cd85068c7d=6000356000811415604757600960086007600660056004600360026001237fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 b89d4effa036fdd9714ea8d2909ac77aacc158a9d5f733a49c90f00af95c7a40=600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 bf620126fdaa0bbd11bf7624530fe444f68eb0ca8511e41316cb8c119e05c292=600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -113ad2cfcf913857d0dc5bbaac973be86da8da32114708fd235aef697aff0e55=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001247fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001247fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +113ad2cfcf913857d0dc5bbaac973be86da8da32114708fd235aef697aff0e55=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001247fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001247fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f69e49d7e6b3de110b1be4e148e271e1b9ba7d061ce06a202f6353ec4690299a=600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b7dff3fc909477303c54bec6ed33be91b00b66f8c6ac80272cd379c3171b9b24=600960086007600660056004600360026001247fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe d80182d7a88eb5a2daf5b0ea6cd6a707a1633bc99ff96952c953c9df56d9a81e=600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -26b5bc19c87e4c5d225dd5e8bcec86089b8d177a4139c29050f87e7ca4eb2720=60003560008103604657600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +26b5bc19c87e4c5d225dd5e8bcec86089b8d177a4139c29050f87e7ca4eb2720=6000356000811415604757600960086007600660056004600360026001247fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 07dba075729f7d3a9ef6119d5c6675eb56146597942582040e967c7390dde883=600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 bd9d506b7f4f2a50d532e0e83e5609b54dfce0d54a8c54c3a1c225d9b2783eb4=600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -3fe65acb20e830f3619ef0632503b60eca4336d71bc659ad0ad231da07e80652=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001257fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001257fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +3fe65acb20e830f3619ef0632503b60eca4336d71bc659ad0ad231da07e80652=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001257fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001257fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 060a850ac93dee7f0f676de2852fe8ffd2f198696fc61938ff14ca04c62eb50b=600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 54c5078af4523181c6ee17a52f63a18029faae11b06f7328da3618b34ae738eb=600960086007600660056004600360026001257fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 12562f84d5161185148e125f2ab2daebcfc5de79299459bfa6f1d56e2219644f=600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -eb53fe99ce99a4bb6770345142474aaf1a0cab1a7d647efc0d205796611c50c4=60003560008103604657600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +eb53fe99ce99a4bb6770345142474aaf1a0cab1a7d647efc0d205796611c50c4=6000356000811415604757600960086007600660056004600360026001257fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 6306f54c0faccf8f2946b4527b8a760f5caf5734fb951557efdc7cc2b7265020=600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 dab38748f11aa52dc375f7c80dabb1f52c66ee8fd11eb77a8b170fc11e061df7=600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -547da97da2db8099372801d9957365e6abef034a61b062db00b448c1d72300fb=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001267fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001267fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +547da97da2db8099372801d9957365e6abef034a61b062db00b448c1d72300fb=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001267fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001267fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 05bb935133313a3a5e317736000032b833292e0569793a0976e7d08f6cc627e3=600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 e0565c2e19f768dc678aed3b504c568bf98a98e870942f4153ddea01d9b17f9a=600960086007600660056004600360026001267fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3ba1210d65ebd6e8c729050cd990472bae1d52e5ffc50ff724c8a474569c29cc=600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -ac14c89491ab4f9496852b6faab382ab873000a20dd939df3c754367a66754a4=60003560008103604657600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +ac14c89491ab4f9496852b6faab382ab873000a20dd939df3c754367a66754a4=6000356000811415604757600960086007600660056004600360026001267fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 eef1a17bec5196611cef1df091a0a6dde2c5b11d6a6188e51f617f0eb2bd4362=600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f7061682ca29c7948fbc253ef98d164d3fc9adf4706e186df381154aeaf040d2=600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e8c24645ea676418428a4efcac2ad3daedf009e6a4279013c0fc44b01c0989d7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001277fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001277fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e8c24645ea676418428a4efcac2ad3daedf009e6a4279013c0fc44b01c0989d7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001277fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001277fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 317abde5a92153497b8bf486243c4656e43437380e6e3ad03ee7e170a989addc=600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 29fa741fc890c810301dc9c0e20eb8e2e5ce9662cabffd9e8e8667e400acbc1c=600960086007600660056004600360026001277fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f00036cdd965cfff85830d094bc0fbb3e0e9f9396cf456f5114555d6bf7a3d28=600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -18c2b63211ef4a0dff198473fca3cb1253b164fb917ae1cc27bf7432f877719a=60003560008103604657600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +18c2b63211ef4a0dff198473fca3cb1253b164fb917ae1cc27bf7432f877719a=6000356000811415604757600960086007600660056004600360026001277fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 578ed7aea34fb9053bc80d93af61003d2ab5c2f9683f448d0b010d666e8646e4=600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 94b5d42885ee094de03227f6cf52c99df51f7e7108c3522167b18fe424da7f45=600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -242013a89507c05b17c04fad0c6a1fd52ec3fa384f40b395bd3681764cc8f4b5=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001287fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001287fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +242013a89507c05b17c04fad0c6a1fd52ec3fa384f40b395bd3681764cc8f4b5=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001287fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001287fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 1d739df75b88d7a314195f4f6c2f103966591fbc40af5d85ea7b260cc4521b39=600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4675b56405f82e43e19afe81bd3178b59679476fa47adc0fc1c0ef0668180933=600960086007600660056004600360026001287fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe d9e877924f288d2a84a86fafd7ca9b9cb75ba9c4eb501fcc9cf92f81c21387f5=600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -1561ca76178e8448f44830c669acf2e17d4dfb2946d78671f1ef5ef056a91236=60003560008103604657600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +1561ca76178e8448f44830c669acf2e17d4dfb2946d78671f1ef5ef056a91236=6000356000811415604757600960086007600660056004600360026001287fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9845c3d252553432dc173193bfa650823b5beab40b61737394fc0d501f675ce1=600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 b5a60844fe55cc6a04b5a58c0dd0f7c96d6053a66bd6bd6b8f9c9ce3fe2c1b13=600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0ca96f543bb78527612ba046247c61bb79ac58caef9e0aa5cd2d9fbdebcfe084=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001297fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001297fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0ca96f543bb78527612ba046247c61bb79ac58caef9e0aa5cd2d9fbdebcfe084=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001297fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001297fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 923910e3d6e8be73445eb3f993ff3d52d4a9eb2ccfb110d7bcff3053d5f8a18b=600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 47459c3386e36a6463108e07ed3a84a93579094d7a6c45acf3b6c836c7fc1d93=600960086007600660056004600360026001297fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 51df9d18d6e18041e83f5814c0601a00925b8d4b1e66740d07cbcfb5cdd4e569=600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -e29cdda491ea2a40f56672b3d4dca382dc051fa751a9a8f945365cb9beb12c5b=60003560008103604657600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +e29cdda491ea2a40f56672b3d4dca382dc051fa751a9a8f945365cb9beb12c5b=6000356000811415604757600960086007600660056004600360026001297fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1667790fc49892808e26dce42b9067024bdf7447c14be38fb4f0fe7affc70315=6009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 0e272b725152fa9efc4db1e64ea68d0d18409eb12a4b5b860e43ce7d2c73c763=6009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -f2c7922a8b3563bfe558a8f90297876c17a1aa7406ac289377f11116a5f25125=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +f2c7922a8b3563bfe558a8f90297876c17a1aa7406ac289377f11116a5f25125=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 2fed7310cc2695527528578e0627bcbe1b48027db89c32d9ec573296daf407e9=6009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4c7781b662b945645193487b17f7bf6547b9e7e68b9bee00333a79741d3bb7e5=6009600860076006600560046003600260012a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe e611756da0056f0b984c4171711eb0f66e4b424c8da0258c9a3a45844d8ba412=6009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -5fe2aedfa5a4f2007d352078679cf620e88aa4772dfa8039b45565b6ac331e45=600035600081036046576009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +5fe2aedfa5a4f2007d352078679cf620e88aa4772dfa8039b45565b6ac331e45=60003560008114156047576009600860076006600560046003600260012a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 0948b8c75705dfc2c5eb08854fdb967f3c2ba10b13cf9918586d3947e5a4dbc9=6009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 89190d44147f4de08c240cae6e964fb264d896bfb55b3144e29ce300fdc96f99=6009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -4600118ac1c8f2372c55101463872f47235d57258d4a4111fb5b52caf9326629=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +4600118ac1c8f2372c55101463872f47235d57258d4a4111fb5b52caf9326629=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f349b9de8a276965f5e10044c8216ea5a15357f1181d486ea43cabf4ec7b35f9=6009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 94bb4b7630e6236592eb2022c26af4348b5c4b2a6c70df6bfc4af5c9865f4b3b=6009600860076006600560046003600260012b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f998b8658be28a6457ea25769ba94ee4393d48201cb7227e55ff8748591a1188=6009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -b7d856c286c7e4524c27bef823fb2862ed08e5f782a4897d930e5e51d000f0ce=600035600081036046576009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +b7d856c286c7e4524c27bef823fb2862ed08e5f782a4897d930e5e51d000f0ce=60003560008114156047576009600860076006600560046003600260012b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d330bae48ebd477135f0170a55250b1ea41526c929f4656ec937096354570bfa=6009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f03e8fe17989acfc4a6767d5d181e6740e488f351c8805316480a128c6fc8554=6009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -570068bb31bf808d763a485c572af81549bd7ebf4fed4090529f430fc2bce49a=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +570068bb31bf808d763a485c572af81549bd7ebf4fed4090529f430fc2bce49a=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 3cc1dd35f1bf78480d13c4c894480977f2b300ca54f67ef06b5be08f35c0f4a3=6009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 95c308319e3d077daad87a4f138752a2797f30ac8d9ea936a9591519c336e490=6009600860076006600560046003600260012c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 1987e07f43cec087446d698e5300c17ecc08a957270483ab7bf61b3fd88a32ee=6009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -075a655ef405ee084855076ead77114ce16ba75534c41c2df8a227c2abc38cbe=600035600081036046576009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +075a655ef405ee084855076ead77114ce16ba75534c41c2df8a227c2abc38cbe=60003560008114156047576009600860076006600560046003600260012c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 6fc0db48d2bfe1a44a02cb9f2d5603ecc3ab98d5ca6869ee88880913bf165595=6009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 67af5a87f59b54b6495aebb08b1e00b70beb0a985639b252805902c91cf5b0da=6009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d0d4130baf835a9ac84c3046960fb2cbeac37445dbdda5c78dccd9c4487d4bc7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d0d4130baf835a9ac84c3046960fb2cbeac37445dbdda5c78dccd9c4487d4bc7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 709f4839fe8d0f0884a050d814b1d626a9f8d0567811d6739aa7076e428e3ed2=6009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 60146ee47fa94b62afd1de2aa8216652b9c4fca5de013945572c1ad7b8f7ab21=6009600860076006600560046003600260012d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe d1ad091324d6cafb3a6e7b965384d37f945563186e93ffb91b25803d8accde0d=6009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8737af588495dd726c53d35e0b7798a7ab27f475195d025ac44e2ed2e9f21788=600035600081036046576009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8737af588495dd726c53d35e0b7798a7ab27f475195d025ac44e2ed2e9f21788=60003560008114156047576009600860076006600560046003600260012d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 17435fc237350074a11f982c4c5076ae982d57dde6cc8cbdae863fe5c73170b0=6009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 78608b6aafca30a01a4e2d58553b28a8ec3a08360756a6867ed028f05d58543e=6009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -142ca2d74e56296478c5216fe33a961ad1f909940461e04549921c6baae0d310=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +142ca2d74e56296478c5216fe33a961ad1f909940461e04549921c6baae0d310=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 0c7f89070797590b8d871cd2718ddced23da1f6d9e2573d262df4ff0a0a0796d=6009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 5cc6b3c72dc49a11c01ba68ab3ca4811106946c2d4d346d537c287b96d5cadcf=6009600860076006600560046003600260012e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3a72c1e0c73c0237c7865cb94e391f7b51ffcacafc2d7fed601932b62baaf063=6009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -f86bf1c45ec93fa6ae2601ba8809f6b28166dfcbdd4ca89bfba5085553d5193d=600035600081036046576009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +f86bf1c45ec93fa6ae2601ba8809f6b28166dfcbdd4ca89bfba5085553d5193d=60003560008114156047576009600860076006600560046003600260012e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 414a2436837bfb656681f8d74b5e8cf83f54992a290da8f0b624cb5ea3caf7d3=6009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5d1bbe989d4ae4e0799b20fa98b23ef667b3a1e32452762bf4994b1019e2dd97=6009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -6623366f6cd4c7b146068162d28f663f041bc5c8b3339ce80cce22aa2f4ae91b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260012f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260012f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +6623366f6cd4c7b146068162d28f663f041bc5c8b3339ce80cce22aa2f4ae91b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260012f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260012f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 5365137e4bd42cb95f7f94b3863c699ef13eea46451482b07141ee2f45c29998=6009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3a265e96cc67edc9fd622e9c8f09c11fa540441babc2302c4d213941c4af6d1b=6009600860076006600560046003600260012f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 986b406a1b50d653ad5a07a8721472c38bfb52e3fe523866c11255875968e919=6009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -a88e183c05e66acfb9f4b0ab63d1fc7be8b983a7bf5b74cc42bee90d8f5438fc=600035600081036046576009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +a88e183c05e66acfb9f4b0ab63d1fc7be8b983a7bf5b74cc42bee90d8f5438fc=60003560008114156047576009600860076006600560046003600260012f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9a4714fbdf05813e64e03dbbed4687685e7d5b266a5a3b263166d96f05aedc17=600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 9c38f5b3aebf6c5d2ce8ceb966acb31ae10357ae88d33119516959187ed04c8e=600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -7cddaf41ea4d16170cf19089d3bc305dca174e2b1732dee4903af75bdbeb1b4c=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001497fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001497fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +7cddaf41ea4d16170cf19089d3bc305dca174e2b1732dee4903af75bdbeb1b4c=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001497fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001497fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 9d577cf94428220da28c0b8a41f410b522020d65b5c8e17d639008b8bee37baf=600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 a46a48acd0af205e877799d0c8d3dabf0ff925f3bbbee5d96fb194fe24b3bf82=600960086007600660056004600360026001497fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe bf15ee2119a8c776a780165974b8e644ec7fad1137b404e3ae11108add851b60=600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c1c3991aeac2c3773ca81ac2435e567107bb91dbfc19092841024a675db206dd=60003560008103604657600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c1c3991aeac2c3773ca81ac2435e567107bb91dbfc19092841024a675db206dd=6000356000811415604757600960086007600660056004600360026001497fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 5f46643c97f2b24211b5a01eb1ec97abcd8e40357a4833880ba08936bd09f86b=6009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 d5bec6c1d856f60d273240f18376a09553c3b6c6e0b2e093ae2b86c9ede53840=6009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -805a168fe93920941a8de3eed871020a0cc71466afbfdbfebf23014a272f5096=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +805a168fe93920941a8de3eed871020a0cc71466afbfdbfebf23014a272f5096=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014a7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 1c772d49b2a475db9c074ff23856a86d2cbe0401d9d3662cf754e24744c65d10=6009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 581ed05876c14509f37fa1a0cdf5a1e086119926da143205885c5404ad708b20=6009600860076006600560046003600260014a7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 1d716efaddb4f7e0ddefb5aa8cfb6ef8e92197310aa684e6604f1deacda59608=6009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -489a47f2e1cad1937a3d2716ae929cfce2c7427b5c5bab7721ab15c1c43bacd8=600035600081036046576009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +489a47f2e1cad1937a3d2716ae929cfce2c7427b5c5bab7721ab15c1c43bacd8=60003560008114156047576009600860076006600560046003600260014a7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 0dced3fc01f029d892ea79b06296941552085cc39178218212ad9eced158c3bb=6009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a2418bc5f50747f3642827b929360935566ad83951d719eeab6f09a3405566c8=6009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b596be88d8632a3695fbf7d142d273f419a824262d2c33114aafa7321268cfeb=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b596be88d8632a3695fbf7d142d273f419a824262d2c33114aafa7321268cfeb=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014b7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 5bb542e49eefddf0e2198fc4a16a19b4bb813878d9641e1cf8b21e629c426d21=6009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 dc683cb5689109fc9b3a0f7d1b2ab96e45579ba9dab80fb8c1834607a92f9acf=6009600860076006600560046003600260014b7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 5dee84479d79d9de0436622b99da00b0e821a3a366bbe1d90b2fbd2578305c7c=6009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -7194a6731850aa94e54ed64390205e64f2e9f7ec6939c2e468d1e6052fc9dd26=600035600081036046576009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +7194a6731850aa94e54ed64390205e64f2e9f7ec6939c2e468d1e6052fc9dd26=60003560008114156047576009600860076006600560046003600260014b7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 dac03672fecbc895d39f416c3d5f9287013ac2a4ec104ac5d7916c7d113a8ac4=6009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 450c0f2b08d2613f867e46b74c279fc97f7445a71700ecf036118e8b64ac04f9=6009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b5e2b88ac45fff42d0a6cac5e73ece523a64eeda2c535c72ddd5a3b5b5df2df2=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b5e2b88ac45fff42d0a6cac5e73ece523a64eeda2c535c72ddd5a3b5b5df2df2=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 2113ad0b1d88921edae398c9debb061acc21db749476fcc7155d17fcbc766daa=6009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 2186b1dbb5db112a710d8ea1309ae6fe8421d09a11c159a1f314b270a3bb2003=6009600860076006600560046003600260014c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 449260e60e60bd8833468bd543e381951ef7246d547c3555306b8489f035080a=6009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c9a76debc6fd52dafce119b0d8b6a0579828992afa6c65ad579ebf05d954bbef=600035600081036046576009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c9a76debc6fd52dafce119b0d8b6a0579828992afa6c65ad579ebf05d954bbef=60003560008114156047576009600860076006600560046003600260014c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f78a0051f2cf054be150a84c71250a1b2d94c26b2910b9ed65c488f35752529c=6009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5545873eec9ee46ecc7c3c81b487ebdc6c82a079800571930878a60fc3d0f3ba=6009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ab05d4d536f135f8b1563f7dbfa5eaf895fee2c78317d78c0c4b3ff3de1b9457=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ab05d4d536f135f8b1563f7dbfa5eaf895fee2c78317d78c0c4b3ff3de1b9457=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 35537ac9b48fe5c3ab0a1786ab4fe1dcd4c5a486a205c4e2c2c1c7035a83aadb=6009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 bd0735179d1d2c7387f5da8032866aa13032c49ba14d4a93297d87b911169513=6009600860076006600560046003600260014d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe cc964f4714ba3ef4ed0875a122eee444ec057559bd5f82c7f7aee62f332f7e19=6009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -e6672f781e8b423031409c2541fc834d2f9c30781c3174774eee3634cbb102b4=600035600081036046576009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +e6672f781e8b423031409c2541fc834d2f9c30781c3174774eee3634cbb102b4=60003560008114156047576009600860076006600560046003600260014d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 ae779725a8c98b7e66d84c9d84d9ece6b29f197d3c73da4f8edcc3f0bb9cb2cd=6009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a61df624f6e8f13a390caba5e48e46833da498d66300d2a7edce56538ae76d5c=6009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c13d93fa7aeb19705ad16a112cd7adb75159db5519fe9106d2e3d3ae86098cd4=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c13d93fa7aeb19705ad16a112cd7adb75159db5519fe9106d2e3d3ae86098cd4=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 9d7b3eb3bc6c20059ca181d0ca7f23625b2d6140301a4a8fdde1d7118e848de4=6009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3b0476fdf948756ddd558634f40d1c232fb83eabc23a9cbe974c807ea212147e=6009600860076006600560046003600260014e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 247339d44499a3c740cef516958655a4d8bb7655059316275dfbef8d441b2087=6009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -e5561ec1d724fe56c53bfe7160e9fcf689df1ccf97606a35f6065cbd8f9d8f22=600035600081036046576009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +e5561ec1d724fe56c53bfe7160e9fcf689df1ccf97606a35f6065cbd8f9d8f22=60003560008114156047576009600860076006600560046003600260014e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 e8cd4486cb70670131d053f139904e3a60073d6dae6830523acee4c3f1ba5386=6009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 d55547540141b5c2474116865a25c2074b577a778273ab5da0e552ccf0cfaf02=6009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d2b888a1e4f0215babb30d4bde4cacbf0f10d774ad6eab3897d254ecce84dc4a=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260014f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260014f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d2b888a1e4f0215babb30d4bde4cacbf0f10d774ad6eab3897d254ecce84dc4a=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260014f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260014f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 86d603dda136eabedebae7b0c92e9ef908cdeae1a7c64b8ea9a1586e4322df90=6009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f4830420556f48087180be5a547eb617b02954cac5d0f32e1a4475061bc53dda=6009600860076006600560046003600260014f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 1095b336e60f4181c7fcf952c990e25c06bdbe0172bf9437b3de45697970afc0=6009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -11d7ebcaaf4190d5b14d989a7e81d0001ebcc03063d7c39a8d0259a96aeed61d=600035600081036046576009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +11d7ebcaaf4190d5b14d989a7e81d0001ebcc03063d7c39a8d0259a96aeed61d=60003560008114156047576009600860076006600560046003600260014f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1d37ad3ecba693e5c7bbb335635f6d523d8a62ece84d8342fa2618b95d1809aa=6009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 147dbb70dd39330bc7810fac0bdc7ebe79cbc820ecf63273a714a2479037f4ac=6009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0b17087362c519279c47d90ad072fd1313d3cf7e2cd5f38d6479769c36a082b7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260015c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260015c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0b17087362c519279c47d90ad072fd1313d3cf7e2cd5f38d6479769c36a082b7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260015c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260015c7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 5bd1b9546aa94ebb8530c1751b31c48c7b52ddd6b79734be7846dd857de86546=6009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f70a86737a9ce9082b30da8f1a40ef6726d7bf11acf24fc7532a3997d972347d=6009600860076006600560046003600260015c7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 14fdbc5e86fccbf2259ce355c990a53abf6f403986ee97062032787fbf2e5a67=6009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -bb2dbfd0fecf67b886c881eb40a3bf1b7e23e2d6dc1fb667ac03b2eede5fd249=600035600081036046576009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +bb2dbfd0fecf67b886c881eb40a3bf1b7e23e2d6dc1fb667ac03b2eede5fd249=60003560008114156047576009600860076006600560046003600260015c7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 c8624036f56a51f08b2ffd35faf49529eca29e28af035b0ae0d50ed86db706c1=6009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a2e0374bc7857327c8ba35ffff2b5f76b4f3bd5d4c1c8eb1226e70e5a7a0471d=6009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -12c97dc5ea9b69cbc61eef6a65b2b1f5bc056aa512b6ef91b358c279ab15f60f=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260015d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260015d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +12c97dc5ea9b69cbc61eef6a65b2b1f5bc056aa512b6ef91b358c279ab15f60f=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260015d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260015d7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 9387c7b6187f6901ff27d62c398a4b1b5c9127990050bf58eb58eb89fb1dbe90=6009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 9e8f7a4f1617ed590aaa165a5347da8947a15c535ef51e3b8e1a07c885cb3c2c=6009600860076006600560046003600260015d7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe a8d2e6881ebbfcc1852e0c1f0765a3e056b190e1cb2136ed1573983702125a89=6009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -644f7c153874c905f89f6bff11a70de4244ce8657a1428e6d702b596516f473d=600035600081036046576009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +644f7c153874c905f89f6bff11a70de4244ce8657a1428e6d702b596516f473d=60003560008114156047576009600860076006600560046003600260015d7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 a3e7bc89de3bc95768a31345a9b17dc068a21d0acfe2d0faa50bfee527abf1fe=6009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 522eb3957173b5fa70095ddefc445e52747ab61a57a6cb6ba69dcad3a8a61c23=6009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ec8cd5ae508c638841ef91c02728cd418d3328a77e0a3de8490c7c43e9fe2edf=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260015e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260015e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ec8cd5ae508c638841ef91c02728cd418d3328a77e0a3de8490c7c43e9fe2edf=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260015e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260015e7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 ee4037bbe88c11fb2fd47a485b421fcb12ef6b6222eaaa5185f2fcf98aafa827=6009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 791540cfc11716b0091faa24e4bfbab6224a6fa7d15b46b9e7c312087fb471c3=6009600860076006600560046003600260015e7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 8b60bdb6d569bc8c93db1524cf0c906e8b489e801f337865b4768cab3d02bfe8=6009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -2a7a2d436d5028b5cca65e6a4ddbe43e79d41bbe8b194946b650e8a7ae4a95f1=600035600081036046576009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +2a7a2d436d5028b5cca65e6a4ddbe43e79d41bbe8b194946b650e8a7ae4a95f1=60003560008114156047576009600860076006600560046003600260015e7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 3985e89094ec6add1a5fec4e9028dc868618558120e379b9a32111d76abbb722=6009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f406f382d6365894d2e79e047bcc8318eb362b3009e0c24450fd6dc1ebc09802=6009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -cb90f8f8d1399f09cc59afb30b2e1d19656593f908a340811c22743c8ec06033=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b6009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b6009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af1506009600860076006600560046003600260015f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b6009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f1506009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b6009600860076006600560046003600260015f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af1506009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +cb90f8f8d1399f09cc59afb30b2e1d19656593f908a340811c22743c8ec06033=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b6009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b6009600860076006600560046003600260015f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af1506009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b6009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f1506009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b6009600860076006600560046003600260015f7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af1506009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 18563cf49ecc84c88fb26dc80586b5505720918dda5d64886a0183843ed1b390=6009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 cee67c20632de89651377f47b8b4d63536aa1892d81cd153babfab74aef85556=6009600860076006600560046003600260015f7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 9ad1f5391eadcbcb99b3de4ec3ac3fc692025d0068434f706b35245665db16ea=6009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -f7a8515356cea83f5aad1ef8aa7ec797a8595f81961c283df205f50388517961=600035600081036046576009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +f7a8515356cea83f5aad1ef8aa7ec797a8595f81961c283df205f50388517961=60003560008114156047576009600860076006600560046003600260015f7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d1eab8fea44614eff5970e1e7261a183641d737cffd761337cf19e11a1b56b23=600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 edab2de8e06c42119704196b4143f60e32a0c6896327cf03d59eed9ae643cadb=600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -7617ac597cc32b4d5804938b024729c826a571db621b6084c3387028abc7a5da=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001a57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001a57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +7617ac597cc32b4d5804938b024729c826a571db621b6084c3387028abc7a5da=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001a57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001a57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 7044d816d041064224679b185ba14bbc395c4c8c1a2fb2c219e6c9a75107e8bb=600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 45728a2ac58cfda8b05d4fa2a87108efd6f608f2febc22b54fafce5b827599cc=600960086007600660056004600360026001a57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 546756297ca7be8134054870e2fdecb2baabbbadb7802f85546ad2565bafb142=600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -623cb76cc7f263283e14a83debf2be6d33e6387b7ca4c291adabeebc28b6cf73=60003560008103604657600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +623cb76cc7f263283e14a83debf2be6d33e6387b7ca4c291adabeebc28b6cf73=6000356000811415604757600960086007600660056004600360026001a57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d97882037d93f9e6a488a09c902811b351a9386d76e4d6917b3d4dde713d4307=600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 3727a46ef1cf11f260d99eca5376cf92bb901638f2320eb0d4c1a1ad064f872a=600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c3dab4fbd966b4bf6be70ef971bc0cf0ea416edf2d43eb32f17205c1f06f7cba=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001a67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001a67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c3dab4fbd966b4bf6be70ef971bc0cf0ea416edf2d43eb32f17205c1f06f7cba=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001a67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001a67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 905e8d8f6cb731f9c4eac2508b3fbdd103b4d1f9a220ce70b9cacd3b06de8ed9=600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 9170a721847222a91f022445156dc1f7e22b2c508241d29b6034ce8ccadf051b=600960086007600660056004600360026001a67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 089e0113da900c9baf841ee09f9976c1d5fa817a4f66301005fcae69fd2851b5=600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -2172a5bbf7248de069dafb926cffc6b486cd3f5e7363cd67e6d9bb7e09d6b987=60003560008103604657600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +2172a5bbf7248de069dafb926cffc6b486cd3f5e7363cd67e6d9bb7e09d6b987=6000356000811415604757600960086007600660056004600360026001a67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 aa7d40c64d7b03188e2196062bfc3145a39d6007c5ff6241669fab753e1d1e22=600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 68630c36bc83e50c031d5a843b9f69c87a31262fe579c318afb46b09f6fd2b80=600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -aa4683a35fd38194581d7a313b9d03d3c09f0651550f7ecd6bee2890ceaf2842=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001a77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001a77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +aa4683a35fd38194581d7a313b9d03d3c09f0651550f7ecd6bee2890ceaf2842=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001a77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001a77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 4c7c09173ec8b4b0bc4f84eea4836c54b13cb5fc9a2001256801fac4b73dcd98=600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c57ce6f6d2a0dc44c1b5ea88555ddfeba94c7b5a90e88d099d62f24b93644a49=600960086007600660056004600360026001a77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 8d70f65be4dfe1874039f917afc337fc0f78c9d73ec0cf6f87952407479e26ba=600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -a2deab31c731cb19a32ee81b5dd1fb8dd0470eefe87bece2fd3fa79fed1f1efa=60003560008103604657600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +a2deab31c731cb19a32ee81b5dd1fb8dd0470eefe87bece2fd3fa79fed1f1efa=6000356000811415604757600960086007600660056004600360026001a77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 c36ee9b66f33ccab08ca07a6652201f082d2bd94eb36b04daadd893dccf6b965=600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f430a70af6677071abf68b854672da24115e8d63aaa840ad0e97dc1308a97b3c=600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -622d029430a2cc1137ab7ba37a468fb2bb3605528bb5ce612fc1b1e51cd92473=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001a87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001a87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +622d029430a2cc1137ab7ba37a468fb2bb3605528bb5ce612fc1b1e51cd92473=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001a87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001a87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8a6a4726a21f9b7c1a94a620ced3d9fec8a69190f8029c2ea0bb0ad0938ed425=600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 ab14c2fcc9ded0061d67077862e0acc84a9e5482e85859418fcacad7212d4685=600960086007600660056004600360026001a87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f1fbc47491951df62388ad0a6aa79863a6223d9e97069a12ed84896fdb947444=600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -648d9c3d8273fcab8e7b98a3d748652514c00cd53c9c542846d8fc152b554588=60003560008103604657600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +648d9c3d8273fcab8e7b98a3d748652514c00cd53c9c542846d8fc152b554588=6000356000811415604757600960086007600660056004600360026001a87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f19dfbe8a65ab6d3733b1b2e67034aa0eebbd4b47b53db891098e6d1ce93db5d=600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a72f444d49095ff1ca7447104f75e88ac9870f742c100f62df082257c26946fd=600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -33704028c14ae91be0d7da306465314c2bbdf085bb687c43609ef8ce7df5eab8=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001a97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001a97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +33704028c14ae91be0d7da306465314c2bbdf085bb687c43609ef8ce7df5eab8=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001a97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001a97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 ee898162a2c27aa90bc90d003ce02bc1d506fa8788cbe3c69f0fb36f3be2a2e8=600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f7a6f24172fc6615b21e4fce5d6f8d37d9250dffab35bf76320ea31a7f989b76=600960086007600660056004600360026001a97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 0259856d6aef71d5d73c6369a5b22de974d2b441cf01c6e8add0f29039a7e21d=600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -dad74d4465d591ea226d9264970f547f9d4b7f6f9c80fd069873d7669d3f13a5=60003560008103604657600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +dad74d4465d591ea226d9264970f547f9d4b7f6f9c80fd069873d7669d3f13a5=6000356000811415604757600960086007600660056004600360026001a97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 295601473c4153b15be75da0ea7f2cfc9f5b402319469b549b78ae66b1392e01=600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 6eee4cca6270f0aa318bdae5d978343e4d6cd121c1e07fbede1951e345114c3a=600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -1bfe22a37bcb20eb9485eee47d820daf3972aae460efc38c72b2dfccea7021e5=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001aa7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001aa7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +1bfe22a37bcb20eb9485eee47d820daf3972aae460efc38c72b2dfccea7021e5=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001aa7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001aa7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 04da003845cd78215fbcc2de15facdfe22cffe9724e0f31825e70706beed643c=600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 091fd439ce89bd0d7c76bc50722fcd05bb1a406d2ff29addd449576cba3e396e=600960086007600660056004600360026001aa7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 7eae079129300611085a8201bb2748f6e5d0086df9301207fc7539f774657776=600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -03cd8ab90e3393d2da8f899965a864a80b0287674c891e7a84761286f5922f99=60003560008103604657600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +03cd8ab90e3393d2da8f899965a864a80b0287674c891e7a84761286f5922f99=6000356000811415604757600960086007600660056004600360026001aa7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 cfaa42b334629e86f0d984c20cc5d2d72fd634f816658c493e080fad5577c92c=600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 0cde0e487762e59d9178c148d5669503e3e80b9e0b0a7cd4ef2aeb0b043d49df=600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -656b84b3aa8ec81eeca08cf8c56e595a45e32076429dc249c91e7a5638d7facc=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ab7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ab7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +656b84b3aa8ec81eeca08cf8c56e595a45e32076429dc249c91e7a5638d7facc=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ab7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ab7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 38ed1b839b2e14af0ecfb0beba968e9ade19702be2c7defd53f01e68c263e6d2=600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 e39774a762fb20a88645672dfc2c74ce0822560179cf7507d5ddc05ca1481ef3=600960086007600660056004600360026001ab7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe a3e5a64802f89fce1f32efc513b486ac0820b0b34685b8fb0737f9a6b4180a8c=600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -24efcd39ac3cdf3dde99e1b504caf4614b03d4f43ead5f9beacfe8be4ae816b3=60003560008103604657600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +24efcd39ac3cdf3dde99e1b504caf4614b03d4f43ead5f9beacfe8be4ae816b3=6000356000811415604757600960086007600660056004600360026001ab7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 465d137cae2495e4fea7763aa4da24bfec43f79e4039aeed2631000950c0e3dd=600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 bd0de9ef240e2ae2c3dee263eb8d295d979357922169643f7fbad4fadf3203aa=600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -4a91f97ac5ec001bcdaba076904646eda8d0911267ce0bd3f7816d1b0b2a381d=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ac7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ac7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +4a91f97ac5ec001bcdaba076904646eda8d0911267ce0bd3f7816d1b0b2a381d=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ac7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ac7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a5512c98710041a04f287685c1eb58b7e9ef51dac1b73198c3e891cedb404317=600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 69fc317a70e7d65296a306efc4741f68405423cc089d4bb14aab766838b3e152=600960086007600660056004600360026001ac7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe e79010d4bf814f5120e3396e358b55653ca0a4360bda3397ac2ed928a6c2a015=600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -92375e3fd5eecf61074e7259bc7e2e32f83c71f22da2cea0ccddaf6022323169=60003560008103604657600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +92375e3fd5eecf61074e7259bc7e2e32f83c71f22da2cea0ccddaf6022323169=6000356000811415604757600960086007600660056004600360026001ac7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 c212f1f96138ae71c8933e72aa994bd3e192bcc21a09c6d767b078f150f4553a=600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 c1739198be2c296443151fabb12fb05b7f4ffe17443adbeab1c7fed63a56a882=600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -5bf1a319391892e8984f26d09759eff4e0d2e5ebfd94c92e82cc668ae379d931=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ad7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ad7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +5bf1a319391892e8984f26d09759eff4e0d2e5ebfd94c92e82cc668ae379d931=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ad7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ad7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 545be1cdc1c5a237b85abee063d9120ea2a05fa6925ff6b0b33934f610461832=600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 fedf639ff904520415f367ac44356cb354f4bf3edc09eedc5dae8fc35d770b37=600960086007600660056004600360026001ad7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe d461f93244983a64bd0b0382e66618c6a20f95e121a0d824906ab123e5ed790b=600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -714e679483bf1a87a19bfb1cafc948c27a6776fac302505f89675503d4d31faf=60003560008103604657600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +714e679483bf1a87a19bfb1cafc948c27a6776fac302505f89675503d4d31faf=6000356000811415604757600960086007600660056004600360026001ad7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 92a2f94f47279694ebe05abea98e523dcc77834cf0aa46b71dc20fffabeee61e=600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e25445ec2ded00e9e890b3a5adf8a6be5ad404bc6b59af04ee9043b555030ebf=600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -cf3e714196c6f7cc168f3149daf08cae9eb74da0bd1096eb6dc3826318b38ad8=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ae7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ae7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +cf3e714196c6f7cc168f3149daf08cae9eb74da0bd1096eb6dc3826318b38ad8=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ae7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ae7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 39280436baea12152a641f69ec1915b38370be4ec75797802783c6225a57c7ad=600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c9e403e13ce264fa6669e004e8e519a4b3355125bf857f5eba1e7a04df1426f9=600960086007600660056004600360026001ae7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3598fd8bac38c5ab3fd4330ab554809e1911d8bbe08762f83a1686b68c6c6b6b=600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -eb8f7a432c7cda4f93de0e9b1fb9894f1a05a5a8b3a64b8d81e0807c9614d063=60003560008103604657600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +eb8f7a432c7cda4f93de0e9b1fb9894f1a05a5a8b3a64b8d81e0807c9614d063=6000356000811415604757600960086007600660056004600360026001ae7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 18028922015b199d55fa28bc39c483b5dac60dbd99f2647189299646209d3f4e=600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ff43a4b6bd4f497c81600f4b31f55457e17a0f2b8e51bddcf1cb73855a68a642=600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b813fe4e9ca8b8d5eb9de231f8577ca1dd344b0d804ec942b5852740b680272a=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001af7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001af7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b813fe4e9ca8b8d5eb9de231f8577ca1dd344b0d804ec942b5852740b680272a=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001af7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001af7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 34f0a9b3798dfc90a5de90017cc9e9225c2db1ef43fdc4acdb6ac0632ba7fe8e=600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4bdabc9cc4cd2dca72f8be241b8ce0159385a80f03ee15e267901c1ad0137886=600960086007600660056004600360026001af7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 6580f3abd546f8acf7550390002de2cb77194e9f4a1552586fe1669e2d6152eb=600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -3b58ce1ccb1bff45ac0377b154d262698ef5951667d644d24afc8b5228b1e368=60003560008103604657600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +3b58ce1ccb1bff45ac0377b154d262698ef5951667d644d24afc8b5228b1e368=6000356000811415604757600960086007600660056004600360026001af7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 23ac936ed2f76cb2295e9492fb292f61eb377fd35de083dfaa32caeb883492af=600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 595b56b882e1c748c6ce52746e5aaeacf5829509d13e566d20766708951b6de8=600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -1c79ff878b728067cceaa9dc5013ffc81bbe10a6b35b9ec68da3b7cb597544d5=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +1c79ff878b728067cceaa9dc5013ffc81bbe10a6b35b9ec68da3b7cb597544d5=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 fe60968b98e5713e5717de453aa6e7f59607afbc23edad154615882624e22a89=600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 79e65b2e2104a8925e1bfe24aa5f1836fb779bdc4779335b77d1471474c79aec=600960086007600660056004600360026001b07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 93c5046ce9a0ceda9b15fc5973038054e3fe198bb5499252667e528910761b60=600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8f54b1af2c7db7e47322314d4a06b9b46753be55dc629dec8adb17185bf14147=60003560008103604657600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8f54b1af2c7db7e47322314d4a06b9b46753be55dc629dec8adb17185bf14147=6000356000811415604757600960086007600660056004600360026001b07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 375b5d3f62a035eb2b1865ecf1e9c2ced18053d504dc4118c8f709fa04076ec8=600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e16ebef2c62fa5608817d23362ea324c2ecfda6f683daf18f9bd3ab4639b81b2=600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0a0b3e15d26674691a7e70d24e04e701aac766224f296a283a45af17275854f6=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0a0b3e15d26674691a7e70d24e04e701aac766224f296a283a45af17275854f6=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 124fe5955b02e4ee014861e023171c6fc4910083f3a53cbc7f5ca0abe1b0c314=600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 5f75a8c43a8a45708325265dee57d9304421d3ba7466dd54bcbd93551b09c6bb=600960086007600660056004600360026001b17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 75535d4885e5f908585c7adb2fe96c6acb264a6a4e08c380050a2479d7c19d85=600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -3af4eb3da62fc565046e8f3aa54fa54ec36914e466bef0c9e4c2edaa5c216241=60003560008103604657600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +3af4eb3da62fc565046e8f3aa54fa54ec36914e466bef0c9e4c2edaa5c216241=6000356000811415604757600960086007600660056004600360026001b17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 6d47c3cb6eff5e142423c64e46fbb8ba1933f14485da3b8e9ba8ee410ae70c8f=600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 671b4f416fb000cd2c078ead172cf30911da23657143463dec98e974490aa0f5=600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -36a77cb26e41113db21c7774e6dfff07da405edf2614a1a57750ac80e724af43=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +36a77cb26e41113db21c7774e6dfff07da405edf2614a1a57750ac80e724af43=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f0c3c5eed4b608a5347b90251412db3927cc57fe5f52446d74b80160026247d7=600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 dae7a64245fd8264485ae19feecd4081291ecb49861c638a4fddeb9a662a5219=600960086007600660056004600360026001b27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 928e010688153b6d9552e29afec10b51d52a3175b8aa3b0562251ab9e0b2fa6d=600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -22170866d87ea1fcf07fcd8c36072b1b399719e0146cfe6ba92c1fc131b7c95e=60003560008103604657600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +22170866d87ea1fcf07fcd8c36072b1b399719e0146cfe6ba92c1fc131b7c95e=6000356000811415604757600960086007600660056004600360026001b27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f1c7bb44fcad11ceb3b9fc7a47fe2e26e00b74bdcd085173433f7b5de6e38980=600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 469439b15a646f36c5427bd314a7f3dca16e45a4f678286f344c91c25b77a5b6=600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -36bcf0fa2bf92207c4936243b58b43c7c5b4a00f238be2427061f4d5b44130bb=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +36bcf0fa2bf92207c4936243b58b43c7c5b4a00f238be2427061f4d5b44130bb=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 78a6788de72feb7e1e104f501e300fbd6894242ea6f54c7d72fb9a1ec0ff8477=600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 781f806cb192042e5088fa9e50fcc5229e6175cb5fb5e28a66ccf48cd2e32f77=600960086007600660056004600360026001b37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 2c0430a512830f77bc21d09623504c1fde5e358d30b51dc419bf0af446aab731=600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c9a36209c89dfb69f00264a028ec5d4a69637f3cba0e90091a2560887bfd0574=60003560008103604657600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c9a36209c89dfb69f00264a028ec5d4a69637f3cba0e90091a2560887bfd0574=6000356000811415604757600960086007600660056004600360026001b37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 4d17d1349fb9f995833650a444ff16c18827e3dd1b38ea6d11d42168dd3e6251=600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 32c1087d13a89661f0d090b01d2908b03da0f044368020440f78a0c5887475bc=600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -982fe1590c1f12ddbb79d0995340fa62d6136498b2a8b26203cc9ac804b2c79b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +982fe1590c1f12ddbb79d0995340fa62d6136498b2a8b26203cc9ac804b2c79b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8c73894e63fb9113d3fde4e1226c32143091f0f6d2938267960d24eeb532095c=600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 810d283fa069e990fc35355a8e236c9455eb032ca179ca096e5e334d10b15984=600960086007600660056004600360026001b47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 6801bf09c7edba24775aae91fd05a0b5a76e29e32ba89f87ec41f9177c00730f=600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -afe2534a3f30e8ab5742f1822626c38b933f2d7eb3eb3ff5d0ffb9c412f47f42=60003560008103604657600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +afe2534a3f30e8ab5742f1822626c38b933f2d7eb3eb3ff5d0ffb9c412f47f42=6000356000811415604757600960086007600660056004600360026001b47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 32e499d14f918180bc38b8a9d48d47d77c2b9b9b774a5e58488fedd697597707=600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 51ef377562e53c18f2c0c8ebca6d060f913794967a619507bbc0a4a91d31fbb4=600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -bf14c2273eb002a265ab4fc35d3f4987e02f56a4e3434e40e719a659c1da7d81=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +bf14c2273eb002a265ab4fc35d3f4987e02f56a4e3434e40e719a659c1da7d81=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 7a912ed2def5530349bcac97a961836f04f79978466c1951b5c4a17626bb8540=600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 020af5e103d2f18a385ff9969ad5a4cc1f7879edd42a44deaff1382ccd6ae262=600960086007600660056004600360026001b57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 1640682cc01269764a2ef366cf43fea58f95405bda149a2148eb0bf9dbab9aab=600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -928a8b2a29b3ccd0643acbb28da10364a97b1493f0f036e34ad3b05447bf956e=60003560008103604657600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +928a8b2a29b3ccd0643acbb28da10364a97b1493f0f036e34ad3b05447bf956e=6000356000811415604757600960086007600660056004600360026001b57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f4477b5d8a992e45bb09f463322830800845b324a87edcb990b242ebcad55112=600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 fcd8e234f92da37c67a6c7290fdc039a69fbb2cf1c8eb14be7749d7ca5225156=600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b08254d18d2253b2d0b26707744350cdd9f6c86cac8a61072807f8e59ba2f191=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b08254d18d2253b2d0b26707744350cdd9f6c86cac8a61072807f8e59ba2f191=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 4f7396a5055abb9752060645295bfabccbe44ac99987d863c4d844dffe9776cb=600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 47817da94d6bfc0115b8f8a4b0998700721e504f5e67f072c3b06e6e908bd57b=600960086007600660056004600360026001b67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f88ebae2e2b0720dcee15414637fb3d3e32446e0867d6ec63de508cf0a87c5cc=600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -a46d8c215ef747e4cf6f9a5daed023e2f50d863301065ec125eec387bc2e95d2=60003560008103604657600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +a46d8c215ef747e4cf6f9a5daed023e2f50d863301065ec125eec387bc2e95d2=6000356000811415604757600960086007600660056004600360026001b67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 dc47640e378fcf9d691d6b599259f7f5527ac41277fd7d5bbeedb957b4d80d49=600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 74f617c08a9bcbb808bb8f7104f7b3d29c5c55bff6992bd4af3e52fbef7df05b=600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -32e5491651bf426b83a9498d4dcba4e2d908a491d48c98e5b863d8dc08f2b54b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +32e5491651bf426b83a9498d4dcba4e2d908a491d48c98e5b863d8dc08f2b54b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 cd2dc524aafa37042e23a0e44f11be551e807bec5d92118babee55c00220ca3c=600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4bb64ecefd2002ebce9297c45a1ce2c990b131db282d56afa78a70aaac859511=600960086007600660056004600360026001b77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 18b26b6ff4b692a2f45c3e1795cd7d33a384e3d5d75dba5fb5c2cb3188c1dd17=600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c5f510ab27978d1ed30488c56fc1431396198a2e7b02c14bdf5a2223b1a314a7=60003560008103604657600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c5f510ab27978d1ed30488c56fc1431396198a2e7b02c14bdf5a2223b1a314a7=6000356000811415604757600960086007600660056004600360026001b77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 060eb32a46ac0a0a127d8ff499441843b9a7fa40b1a616206dc3192ef8c76053=600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 41f21ea7974797fac4d5489776481d7a2b62ee2bf514079761224a7b8e131d33=600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -f58cd0f4b2167441afd6ce239d2bcb8ab537f23d13a8ef0b3438cb80310a625b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +f58cd0f4b2167441afd6ce239d2bcb8ab537f23d13a8ef0b3438cb80310a625b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 4ef5b0b7d82b26ac3d4272e69e908eb983ff9247f872a6b4f8e5701163da4ac2=600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 56e3a592dd11a809a75deff30b01a591bd237f91271ae0d290f1e452f45e8664=600960086007600660056004600360026001b87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 19d81279025ac2acfc0cc45a874ac42706d42f2d8b311d3758027066f22679a9=600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -ab05337b437e65da194ed9c8a563c5ea899b96e4dca691e9169b5c8978ba4f8e=60003560008103604657600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +ab05337b437e65da194ed9c8a563c5ea899b96e4dca691e9169b5c8978ba4f8e=6000356000811415604757600960086007600660056004600360026001b87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 68353f05fc7e97c586eb3b8bea79b0360b0ecd5af70040e76a85eb8ede03fe07=600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 4f6d5424ef81c065114c560a6b9c7b642ed1ba0f7e32729c4f9f83908934619f=600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c1e1ad645a498e3daec6fa098b38f2b1aba2ce869d5b2076fb236d094142fdeb=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001b97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001b97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c1e1ad645a498e3daec6fa098b38f2b1aba2ce869d5b2076fb236d094142fdeb=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001b97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001b97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 714ed27fbcb26b98adc34d507e6e03645f80cc231e43386565c2afaf1f83a3e9=600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 eb3c3c4986684fdc2068398c4684f100ce78a6e3142dbcdd4d67f463d5460dde=600960086007600660056004600360026001b97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe e450e874f29d34b4480a880a9e31db38b01e7bb5bd4693c7e3bd258d0fb701a4=600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -63c1b930bc412b67d7d24253b1d20dd1985b214b72f368a3e6842009d2ec9d62=60003560008103604657600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +63c1b930bc412b67d7d24253b1d20dd1985b214b72f368a3e6842009d2ec9d62=6000356000811415604757600960086007600660056004600360026001b97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 90b4aec00af9accae5e7f5207d4839b95d28df1c249e6f95b0d961513cd1e572=600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ad7d9ee1beca4b66b8bc39911b853419ba26c05f2f312c869f9bc4cb21a99229=600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -6c050fe5c83db884e90b5aa7e7386a3ec77d1e1247351c3e2fc9997a079b22f7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ba7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ba7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +6c050fe5c83db884e90b5aa7e7386a3ec77d1e1247351c3e2fc9997a079b22f7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ba7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ba7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 885031d46e1d825960abd359a762b9bb464573c652043bd5d75eb346d26815ea=600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f557552f010fc2c4caadc4a38b60361d65a83bd932bac36149ee79992531cb80=600960086007600660056004600360026001ba7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 56ffd5c13a4aad794d26796e681d74b8a3384e283301828adb4568dd38b05309=600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -11ef9a4a25acb1844a4b010af5eee70f1351d3edddb4348cb1413d48c2fdee50=60003560008103604657600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +11ef9a4a25acb1844a4b010af5eee70f1351d3edddb4348cb1413d48c2fdee50=6000356000811415604757600960086007600660056004600360026001ba7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d9c20ffb6352c592ed47ce05fc10defad6f2b695bdb61235f4ab457e6fed13f7=600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f587a62ed97890df766b66bea9ec2ef86fc697ee3eff9a248a311f95bdd603d8=600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -2ae87cdc2993ba049ebcfba248401241c35aee3134c3867974cac31c19f50102=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001bb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001bb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +2ae87cdc2993ba049ebcfba248401241c35aee3134c3867974cac31c19f50102=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001bb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001bb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a7ec3e451e4df447640e4faeb5115d4717d6d39c95a4e93780d6f286ac740130=600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 a3da684d2da4a84617d15196aece456f0c6c3410718e4f241356885418334d74=600960086007600660056004600360026001bb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 22c231e7da3c71b41c76b4c8c93e6429b308dfdb59357f4675e2da62b08d2df5=600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -61c9a242cba0f3a0691359ce010ba50cd8401350253c695b7c0009f5ad6e746e=60003560008103604657600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +61c9a242cba0f3a0691359ce010ba50cd8401350253c695b7c0009f5ad6e746e=6000356000811415604757600960086007600660056004600360026001bb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 bbe32aa859c49ab5fb458dfe83d006331f8cb98d1a970cc5978201eabfade8ad=600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a9d4c65cf0b8b6e2c9a0fc33714c44737efd898474b67c009e3266b20ec6b83e=600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -afb0383f74c8fb962e5a94e2714ff5b425e6657c505b382442bafac93e9753f7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001bc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001bc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +afb0383f74c8fb962e5a94e2714ff5b425e6657c505b382442bafac93e9753f7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001bc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001bc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f21d9bc01a0741c0e702b32d09bf28d6749ec517705d1eb7238fd403c2921427=600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3c7ddf8dd24b16f19a47ce5eb3ac90d2128a35049e4ce0ff4b99fade851ca8b0=600960086007600660056004600360026001bc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe bdef3b665cd59dfea57fc602d5017e1e8eb092c15b355dd0456d94789be71e31=600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -4237df860359f33d365a69395d5f321d4d8b7ee1e9166acf6214c0fd4cb5ad0e=60003560008103604657600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +4237df860359f33d365a69395d5f321d4d8b7ee1e9166acf6214c0fd4cb5ad0e=6000356000811415604757600960086007600660056004600360026001bc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 2ea5eeb8ef97f0ff1f8aa51fa11c7213de8e1d1be8f878f77fc98f808608938e=600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 325ad31a49d67fc404441fc41fe1bdcccc34b0f17a6ab6f8238c14f0d0dc97c5=600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e84edbf58da2d1e6f701242356a9ff5c710214cf065f587a6c98d432670447c2=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001bd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001bd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e84edbf58da2d1e6f701242356a9ff5c710214cf065f587a6c98d432670447c2=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001bd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001bd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a516af5aea961e1fac619bc19a11abc7625e9ab59754da20190a65f6acb189aa=600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c1fd32b16a5b0f534498e1d40c344c968069951277a01e791c686185bceb542d=600960086007600660056004600360026001bd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 92cdd0607a0c0d8e28a101fe5df98d04376d85e02863f5bbf3cae30c2d473e45=600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -4439a26104f7dbd9b240afb41bc818231979bc587a218d552de0c8373f61890e=60003560008103604657600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +4439a26104f7dbd9b240afb41bc818231979bc587a218d552de0c8373f61890e=6000356000811415604757600960086007600660056004600360026001bd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 69e10cddc75cda5d4d1ff9cb935650afc2118cdf1db4a3fce6caff616ede500b=600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 b96f19b1d24912ebb702f1c393305b4cf2fc2a1cc9d6ac69d6b33b97bdf38ed8=600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -9781012481f678a36f86a25b86fb52d017479dc87be9a704c6a2d5cddc3e7477=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001be7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001be7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +9781012481f678a36f86a25b86fb52d017479dc87be9a704c6a2d5cddc3e7477=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001be7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001be7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f29704b621a80db5c5ee36cdc261e2a7730f418c374b2e1634cad6dca0971aa9=600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 969208a452514723bf359c36fbe83a921e78b9e24f906637c95c63595e1e599e=600960086007600660056004600360026001be7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f9fd9ca72e3f03cccf514d064261ea2415ba872125a85517f195603bd132e778=600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -7633c312f2d5e65fa6721fba58659feca6ca4bdd05d0bfdc28b1ec3b34513a64=60003560008103604657600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +7633c312f2d5e65fa6721fba58659feca6ca4bdd05d0bfdc28b1ec3b34513a64=6000356000811415604757600960086007600660056004600360026001be7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 57b73f83400b5ef877cdd52844ad09c82b8fe390d58fe63ebb018ae6ea00c481=600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5ad24ba6a729b87d21f517a92ac64f275229d61d93421b2d66982d9a059ba29e=600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -90c69b12e37f9f8ee8ee52cd8e9b7062cf48845e25401c64d52bea5026e906f6=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001bf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001bf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +90c69b12e37f9f8ee8ee52cd8e9b7062cf48845e25401c64d52bea5026e906f6=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001bf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001bf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 baf5c820aa3e58c78f163531e8e2472a5cb184c6e2e6fc32f1547bd84307e656=600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 486ee7d509561e73aaca3f243feb8c1ac4e30807fb2d4577fb582f25e8ac81c8=600960086007600660056004600360026001bf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 4d2c16a28c19d6fb0386ccb9005fde6d62c8ca4a5a30a4c18424f096610c6b8a=600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -5f46a8529b5e1d3b165b4ee0b775d9d441dd780ff7af26154697cdb10199b760=60003560008103604657600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +5f46a8529b5e1d3b165b4ee0b775d9d441dd780ff7af26154697cdb10199b760=6000356000811415604757600960086007600660056004600360026001bf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 aab5ea36b89f5907f0f139b28e0f3ee64b3b4e074b2baf8d16b70356eda8c72d=600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 43a33476d20d5465f15b69b5ac3dcba65e253264b229885b18709f4efe6d513d=600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -440ec0e78611df0b764686eb6810cc37c97827aa13e57ff12201bf021ef0eda0=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +440ec0e78611df0b764686eb6810cc37c97827aa13e57ff12201bf021ef0eda0=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 6e352e2ebd9d9bac28494cab053a3e4d67401baa7484d3cadf318cf18ea7c4e3=600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 1ad9173ac7b3cb4a897a6a58070706acc250504ec6daae074a01ac15c4150fb2=600960086007600660056004600360026001c07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 6fb28d0f57446bdba873fb68f0972bcffda1250fe19012c87dccd30f4e472e44=600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -49cd5faa9fb3e42f1fe31081b56a22ba654ed76197bfb0a2016bd6d6fc1f27a7=60003560008103604657600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +49cd5faa9fb3e42f1fe31081b56a22ba654ed76197bfb0a2016bd6d6fc1f27a7=6000356000811415604757600960086007600660056004600360026001c07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 8e657bb75f00a0297400a3a50e4a6b40c23f255530ebb0530afd60b3c19d53b8=600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 368e68be00e685410b86a60080737fe47b7fc9857b479a25372224c6763df8de=600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -8723ed6741f8d8fb5be14f39f9cbd1b908133c3db40ff77d229f8a6e22f669b8=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +8723ed6741f8d8fb5be14f39f9cbd1b908133c3db40ff77d229f8a6e22f669b8=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 dd628deed7e03429ba283bc2d2898d18cdc98c23fbd11b33a0f3156e733bb776=600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 6a87672c9ee5e435040ce2b29286e062cf1aae0f571a42a3a98d60283779e3c6=600960086007600660056004600360026001c17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 069be315142d5ae52faed421c0aff3f3a6d217a81efb09d7d75a353491e8184b=600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -234b6b37e76484cbcee4b1dd2cce1b2f8d773d64f98df062c466099e7e6926c0=60003560008103604657600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +234b6b37e76484cbcee4b1dd2cce1b2f8d773d64f98df062c466099e7e6926c0=6000356000811415604757600960086007600660056004600360026001c17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1ce96ce059b153a9e8802e6632ea68c611876ad0b238204659161407388fc332=600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2162c46f2802de086aa7f2056f60574bb25bd74b4f005f80529202067321ca8f=600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d5e04f14bd81b88c48371518f9f6ce4cc862b25d7ad266ced28beb79e814a386=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d5e04f14bd81b88c48371518f9f6ce4cc862b25d7ad266ced28beb79e814a386=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 7aaf6a69cba0b1b8f4da62eb864a4b2a9b340d60dc5a6a40ea0807873f58d16e=600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4a004cb232cd1e3a18e12aeca88a7efac99815dcf28292244b346c27e445ff3e=600960086007600660056004600360026001c27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe a2cd69df723f90bafd39ea419d93c4ef4f4572831db7b45cccb7461d902c8cf9=600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -974f7984dd282554276542e774e708d9fff20311c449fd16921c3088553c3a72=60003560008103604657600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +974f7984dd282554276542e774e708d9fff20311c449fd16921c3088553c3a72=6000356000811415604757600960086007600660056004600360026001c27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9bb857c9bebb6c8d81a51785922eb45ba1f92a6ed98738f7fe0405ac49ca7d53=600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2b982e1a87489c81cf9a368fefd6a74a9d9f72ec9c0d0551acadf19ca7bd2273=600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b697e84cbc6834254d4b76d3aae988420d5ad35d4f09ddd95cd4b5c0a00fdf9e=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b697e84cbc6834254d4b76d3aae988420d5ad35d4f09ddd95cd4b5c0a00fdf9e=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 4d96fb0435b0d495988e9e29144bb21494dd1fb222ef9b09fd45bd624135000a=600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 4b22465493b76a6aebfbf2a73ebe5a22f4ef92685c2b83cb99472c4bc7c0f896=600960086007600660056004600360026001c37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3211d35021f25e0987cba652ec37b9e39657ce55a42877fc8df701649ce0cada=600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -f1516a4385c86866869634bf6949cb7fb3d1ce8141ccf858f3ab96ed87447251=60003560008103604657600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +f1516a4385c86866869634bf6949cb7fb3d1ce8141ccf858f3ab96ed87447251=6000356000811415604757600960086007600660056004600360026001c37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 439530133f2228fa8e0dad386601dc9695a2d09a01a803deaaf39ea5162241e2=600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ac6dcf8ae0079e8d984fb01831ad21afbd824fada61ee5fc1b0603c96616ac09=600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ad79ebdd32f48ba8ddc1ce9a9476ec848bd139f9a2ddde614138955d4689b242=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ad79ebdd32f48ba8ddc1ce9a9476ec848bd139f9a2ddde614138955d4689b242=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a4b1246e81e1369d23fb22273dac81fc1b8598cc6cb14f71cb9aeeb00a9d04fa=600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c892dede084f9118b019849b9be25a068558251f5430a4c1921921845ca8f512=600960086007600660056004600360026001c47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 615252e815af8eb1de05741ea6ab2c7d03d00af4eb87e088d341fffb871fe754=600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -5e8e0a54f184c32d46fd08bdade18d6a8d3fccd64c87cba8a7703b38f62c7336=60003560008103604657600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +5e8e0a54f184c32d46fd08bdade18d6a8d3fccd64c87cba8a7703b38f62c7336=6000356000811415604757600960086007600660056004600360026001c47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 0375fa912edf2f7c60cf125aa617f5dd3514a1356545df920965d08c41597984=600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ef168ca331ba8645a99cc6cb80283d220a5ed8cd973b491d4c88bbd9265b0dd6=600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -3f32f88b66bf79172337e14f8f52104b5d200d429dcdcfa6f93192a5d6629782=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +3f32f88b66bf79172337e14f8f52104b5d200d429dcdcfa6f93192a5d6629782=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 b8fbeb85cccd9c76387a9cee0ea09c4e8a943ce8c2ee47ae5b7766dc6fc690bf=600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 2dfb655ecff1501872f5979d451dc466a49c234ddcd8ac8692a36a9d91df4f77=600960086007600660056004600360026001c57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 88b21439bf1281ae594679796592b8952dc990b55d954c2a9915abc9f2703ce9=600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -08496e3e273367dbc053d796145e71454729616fac8c190973153de07904b6a6=60003560008103604657600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +08496e3e273367dbc053d796145e71454729616fac8c190973153de07904b6a6=6000356000811415604757600960086007600660056004600360026001c57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 4d9486b483e2f77620501d46a7caac785c5d2bc18be0bf4d30dd2478d5c7c75a=600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 73762e0d992f8d0ea797598c83cf6a377707170d51e16aedd139629f629c4f1c=600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e9a4c9f4ca05b4b4e9cf162d01dbbf480b6399185a17e8caf0ef41119e39f4b7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e9a4c9f4ca05b4b4e9cf162d01dbbf480b6399185a17e8caf0ef41119e39f4b7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 ea271447fed62860c072b33063cd8090b64081faf695c1bde2d018e826c04d31=600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 813bfd0b2011043a0f2cc1357b62e042d3fc33aeb1e132e58af04f847f1c6746=600960086007600660056004600360026001c67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f591e793f6861eb3c3de8fd1bfa638d3cc470ef12dea27e0164ebd28d25665c4=600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -5f115fc96d83aea046796b3a2506102bae1afbc207f908fc4c9a8e148afb3b6b=60003560008103604657600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +5f115fc96d83aea046796b3a2506102bae1afbc207f908fc4c9a8e148afb3b6b=6000356000811415604757600960086007600660056004600360026001c67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d5335691ff41d95710b99a76303028bf42de25eaf85a8dbe61433792cd6262c4=600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5ed0e3fbb30789c1b44fa44c061ee79566cf2963e02fa490a5ca3b08b23cb521=600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -13e9e5ac7f93cca3980104b053f3ad103533c797703864ed22277f9ce7107569=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +13e9e5ac7f93cca3980104b053f3ad103533c797703864ed22277f9ce7107569=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 380d14538a25f7c64f6b81b5a5e38fe5fab66c7180d90845a8876c938478aede=600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 1d14163cc318001db2bb78675bad098c084799c5dedad0dc12a6428dbb17c6e9=600960086007600660056004600360026001c77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 120cb7b7259f1ed21453a6d1b779c82de8cb2e65eacea355a1e27d0d4035ee9e=600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -35ef132ecdc159990e9b6ad2ceae338a486093fc05b57a770f38b667e95e0493=60003560008103604657600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +35ef132ecdc159990e9b6ad2ceae338a486093fc05b57a770f38b667e95e0493=6000356000811415604757600960086007600660056004600360026001c77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 ac4896171d33303ef20703033f342b17cc1650dbfd30771818344ff0dc9058d1=600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5f42440bcc01b7d5f9ad06ff26a9a8bdecd35acb5ca8699196d4e55edab93471=600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -4e868c4d256b21ed972bc250ee1ac518f9c014dde98341ac2b6d9e565c90f638=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +4e868c4d256b21ed972bc250ee1ac518f9c014dde98341ac2b6d9e565c90f638=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 6f53a391ea3183a124183d8c150ec3266fd181cf10c312cd346b1f4614216aef=600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b993591e9fdcac10016723e14f857946844c0a64303a908a24100f54f9df17d8=600960086007600660056004600360026001c87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 8f3537806dadb3d4a4b60815f850f4ff5ad01e8f0feee907d69ca4cf0ea013ba=600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -0f1b2da59c4b602977dafe4d1b79597d3c8afe89ef9f71b018eb59d076c8a4cb=60003560008103604657600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +0f1b2da59c4b602977dafe4d1b79597d3c8afe89ef9f71b018eb59d076c8a4cb=6000356000811415604757600960086007600660056004600360026001c87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 28f4dd34447648ec9e675bb317c32c8539298c27cfb9ff498cc10e95c634accc=600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 3b1bbf312fdde0d278d6f3f34e606cbd27d98cfc897d447f5f8037028757197b=600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d0cc642242daac82c715d9c71ea0112f8df6106a0745056ebc81dc01104d73e9=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001c97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001c97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d0cc642242daac82c715d9c71ea0112f8df6106a0745056ebc81dc01104d73e9=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001c97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001c97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 b361154f19d72fe35b479160786b939835c066ea168d45a57042771b49d43123=600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3adbb8134114e2c5d77a5c47590159462b2b74eeed2b38c3379bbc3bbe9a565f=600960086007600660056004600360026001c97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3e0bfc127758c9f9ebb12099a868a468389f4f73c69b2db4afd56bec3dd8b3dd=600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -3f2ca8c7e6934176b71288146a8af8e3dca9c054220be767de61cc27ba176ca3=60003560008103604657600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +3f2ca8c7e6934176b71288146a8af8e3dca9c054220be767de61cc27ba176ca3=6000356000811415604757600960086007600660056004600360026001c97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 46dfd8ebec3c8c8ff8adf43651d4cf432fb2343355b3bb1cd230f6063c13b309=600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 857740fd572bdfd1829434b61f42b53ec3f31ac7ef3ad788677b6de599a27a41=600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c3f190c9403fea1726c7123e52f40930bda6a41c98abae21e68add8590f44f5f=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ca7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ca7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c3f190c9403fea1726c7123e52f40930bda6a41c98abae21e68add8590f44f5f=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ca7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ca7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 aaf645f4b626eff209e52b63facf7c9cb088404a4d11f26782d218cf3bc0c06e=600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 280c654513fc9039633ec318ff2bbf0570123a7eaefe2664a3863d9fcea5d253=600960086007600660056004600360026001ca7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 5d02e6a32bc8967dba0b0ad780a853d1d19505d7b792e08c92d94f65f40c96b3=600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -bf1db7109b5b16330b9442b03e834442165ac90fe17931e6a79ed334af1f79de=60003560008103604657600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +bf1db7109b5b16330b9442b03e834442165ac90fe17931e6a79ed334af1f79de=6000356000811415604757600960086007600660056004600360026001ca7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 70421cfebcef742f9487c2db6f68d667ef753858aaaf6c301af352d1b0871e27=600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a413342f8f17847a45f5421ef05f891bb039b7896940c4c503721546b3a11b9e=600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -abc9893ccc2e8bef454b27536ab005ebe0e7693ba75754709b8cec6c6c77bf01=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001cb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001cb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +abc9893ccc2e8bef454b27536ab005ebe0e7693ba75754709b8cec6c6c77bf01=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001cb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001cb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 7560dea88f0ac2ed905efb2f9ba2ee018caa5ab5b25148b9d6fe1c9767f68b74=600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 7254df8898b0191c5de0a4562b34d446bcf7712907f80b06ea9315a8e8f88de2=600960086007600660056004600360026001cb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 7e8ab85fe33c0c8473895fac19e3302573291ac2c6dba89e62e5b9e4699585b6=600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -16bfb54cbf3bbf0e6ccb475c5fd7245ae24f7bfb351e02368eedc9482de19390=60003560008103604657600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +16bfb54cbf3bbf0e6ccb475c5fd7245ae24f7bfb351e02368eedc9482de19390=6000356000811415604757600960086007600660056004600360026001cb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 7f39f7ef0125cfa83ce32a6c4c20af7377a7df8755e37da7d7a1a6389ba57365=600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 1ec250321b9543f1a2b63b55786cb643ca5627b875f2dfa2f3821f4f08e621f9=600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -412ae4e449f6ee919062d19559e8ae94f7017911a509c4af228fe8b6832220f7=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001cc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001cc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +412ae4e449f6ee919062d19559e8ae94f7017911a509c4af228fe8b6832220f7=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001cc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001cc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 e0ccaf557395e255d198d6c34bf27e0aee8d4762711964e57fb9411b21e6eee2=600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 a1aefc889e3adc93641419f664b8ea9f95149d97eb8cae8a5dad4ac9e34b0855=600960086007600660056004600360026001cc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 686770c818dbadcfcd15a05fbc6df2c728d670e1868fa635a9e0e9c716cb26ba=600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -5f378f22ff9567958d9bbc63045ec893afb585a57548203da4bd3c76d680ac32=60003560008103604657600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +5f378f22ff9567958d9bbc63045ec893afb585a57548203da4bd3c76d680ac32=6000356000811415604757600960086007600660056004600360026001cc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9e401dddb0173c98851dd8f2181b97d7a25699de42ae789d25fa9e16feb28842=600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 0405d3537840abcaf76d3b1c998546b198f5b6731723d276b47dafcfb1b9039a=600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0617e94807baea3f5758b9863492443530f4168146a2052aec9d02b47c19dad3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001cd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001cd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0617e94807baea3f5758b9863492443530f4168146a2052aec9d02b47c19dad3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001cd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001cd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 881c8bbef1191c85c0903fedd72e09004d647749c5bb19cc3e9d8711c0f3f63e=600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 27509aba5dd674de97ac3bc3f02ff621cd5204e8c379ea6134382a887bfaf012=600960086007600660056004600360026001cd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 523d1338396825bc37d7d890d5c741bc19ca16f5702710eb0c4463e7dce88a8c=600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c4888914c26f389aa69980067e9024f8180821fd7f2555ad685f6d63a839f4a4=60003560008103604657600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c4888914c26f389aa69980067e9024f8180821fd7f2555ad685f6d63a839f4a4=6000356000811415604757600960086007600660056004600360026001cd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 47d43ea4b70f2e35c0174a4ae1735c42eaecb0c5165f77fb49840a9ffb892c78=600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ca3fa8eddd68904f7cdcf567db56125df0f53cfacdae06877cc59cc6ebf7b96d=600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -f7555bae98a13bc3cbc3babcbbad27008299fe802625d8891e63aa16eafa8c7b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ce7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ce7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +f7555bae98a13bc3cbc3babcbbad27008299fe802625d8891e63aa16eafa8c7b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ce7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ce7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 583e89c83bea326aed85a4a2a8134d938385a5ea79de4ad2579117bae4a51bcd=600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f295d6f7b7cf81c4c473520ee2757f551ae0ce2b97b11eea2eeae988255bf125=600960086007600660056004600360026001ce7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 36398ac27c1816ccf217d9b386b8f7a5be1aa664449309177ab911ba9aad0365=600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -0003dfc581f74bddc1450abd12552dcaf94121bc7295e1fbed29045883cbe066=60003560008103604657600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +0003dfc581f74bddc1450abd12552dcaf94121bc7295e1fbed29045883cbe066=6000356000811415604757600960086007600660056004600360026001ce7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 97dd6dd62fffecc0fc6e69e9a3015126f136fff8a8b372a0228e63397e7b11b8=600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 a5766152b2a05afa2ca57cf3967be5e3867341faa344734fd2b694efafa49f0c=600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b806609a7674f3eb7ef902f665ff511113138d949164be00b3b847f1843d00c9=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001cf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001cf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b806609a7674f3eb7ef902f665ff511113138d949164be00b3b847f1843d00c9=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001cf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001cf7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8764a3fbee18814e6d7eb42c119d88ea6ec6ddf9a5af976075158c867698f833=600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 229ddb8f6d9b8dba7d1178c0ac7f5231f827dc28442056b4ea17fab3522cd271=600960086007600660056004600360026001cf7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 004cd42d73a275dddb68180477b7677ab62e5d6f6057658b78f9063e7c06278e=600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -839cf458c161c9fb3272afc4d4f935159ee82366dfe32b7aa5576b40849273b0=60003560008103604657600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +839cf458c161c9fb3272afc4d4f935159ee82366dfe32b7aa5576b40849273b0=6000356000811415604757600960086007600660056004600360026001cf7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 324f6a027dcca08b9b1c28a8b43984511b72b4ccd7d8d93974a0c6e2bd317115=600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 8adb8a14d90cb3bd6040ce08ca1608ec3f03c1fc6ad2fd13b81d82c66782b704=600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -1f01ea747ddb19f54f9dc9042d65774b8705b8ee7ad09a44f00046ff2a66e6c3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +1f01ea747ddb19f54f9dc9042d65774b8705b8ee7ad09a44f00046ff2a66e6c3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 2d5bafeb06df5023ed65dda8ffe7f2e1baaa45cdfe86c81f1d3bda2fb00dd363=600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 8bf25357302a2ba964bec400939e5db164a9af11273b528c0ebe6109279fc22f=600960086007600660056004600360026001d07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c0e4c6e0704bb5bf9f5368cde41925f637a4de4205a6edbf2b1cbf99c3db06dd=600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -29b933f1d48738476cb6774bbd6fe38268e4a8ca9114ba5039bbf553c092a9de=60003560008103604657600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +29b933f1d48738476cb6774bbd6fe38268e4a8ca9114ba5039bbf553c092a9de=6000356000811415604757600960086007600660056004600360026001d07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 7fcaaa2ecb30302187e61f37facfce1000d5e6b55c42ab7be83c0731a24d4440=600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e214794f819f7b5e1305eaef18f24c1a985c98f158a18d621abe8fd21bc26171=600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e8bbf703e8a2b15300745f8e110a465726c0c318d989625eaca882de89de4817=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e8bbf703e8a2b15300745f8e110a465726c0c318d989625eaca882de89de4817=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 47fe4485c32d3a236868937fe4f5009cc531650588c5b2fc68c41b16469a0a96=600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 f10b6f035e1a56675d8c3b158a752972d25e7a6b881ca653d2a51c07c6a64ebe=600960086007600660056004600360026001d17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 839e3adf3131ddd154706cc442affd253483b29fe17af2e5d53afb7c8e482e23=600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c89f6034d9a030297654740493ddc7a2a5f6e240b29684a43ad6f0fc735cb10c=60003560008103604657600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c89f6034d9a030297654740493ddc7a2a5f6e240b29684a43ad6f0fc735cb10c=6000356000811415604757600960086007600660056004600360026001d17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 27e04042d96f3bfd4bc7ffab12c8e6da8dd89ded025e2190a72c5ddae24b40ba=600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 6789ae48d53a5fcfe44d3bd79fcfe6c5babe219dcb2c62f0c90d461544765644=600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -0a87e0b425c4292daebce0ea27c5f00546272c4638017ac11b4b32b0473afa21=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +0a87e0b425c4292daebce0ea27c5f00546272c4638017ac11b4b32b0473afa21=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 c1faf1fa66ce438c83fdda08f99d9493edc31fc175dc063fdaec53a617021634=600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c39b88b457679ecd4fc2ac6b6327c1e1fc72686b55a811d51832de64d5b1946d=600960086007600660056004600360026001d27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 662889ac99a3ea140e46a9b23c1c0e93c36e424a8b0bf9c470caaa64120f9398=600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -b6670619113d57dc4d111396d11f5d88e79fff101834b4e1bfd5a1c6a97046d2=60003560008103604657600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +b6670619113d57dc4d111396d11f5d88e79fff101834b4e1bfd5a1c6a97046d2=6000356000811415604757600960086007600660056004600360026001d27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 7a817fd5ad0721df230e0495b386b7f86fd2b478ddb25af2dcdb69f3f970e36f=600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 9b0334b33fc11550c7d3f46efbfaebb1d863c986293f3f33700b00f11aa2181d=600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -93c2648c72a95c6d10f6ca25e6fbbb98bfe781fed47bd28b8afa0c2ec546d418=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +93c2648c72a95c6d10f6ca25e6fbbb98bfe781fed47bd28b8afa0c2ec546d418=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 b35e3f5d8e752fc1fed8671de2fb3d95d42c67b490f010162b2ecd624666a74e=600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 064f3d1db755c16a7e8fb51d0b847d4b670641ccd8ada7cea1ea9779e5de9e45=600960086007600660056004600360026001d37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f11bf1529932e01464f2ca2b42783b2805b74c3223cda19f8835c9664aaff6e4=600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -e5718f59f49690be6b36f5d0581b7292b6db85bf0dc6060627b0f728cef5f8d3=60003560008103604657600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +e5718f59f49690be6b36f5d0581b7292b6db85bf0dc6060627b0f728cef5f8d3=6000356000811415604757600960086007600660056004600360026001d37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 1217c0355376c0b2adaac7603b0c744a37dff7a4c3199a5149f1f04aab7cc5b1=600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 075a24ccb35099b1f869b1f84153341aa0cddaaf7dbc8aa1b093bb8833498e78=600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -15766aa9806a8cd8bcee26202bba40881e9e0e8a66db2a4273891512af1acd64=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +15766aa9806a8cd8bcee26202bba40881e9e0e8a66db2a4273891512af1acd64=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 72d686960fe6db035ab23e69f2adce742b03d333f2cb621d69ef03b4c22b6ffb=600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 6d29b72e08ca8356711aa2ee00c1c158beef62ea84cc170c68bf7f7eb7175e83=600960086007600660056004600360026001d47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe e14d4d4b85f8ffd1c95fa85d76010482ebc3221c9d146fd987e0be8bc601d231=600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -be8d399779cb2f1b616afb6174ba07ac61dd26cf04c3bea05f944e85666d81d4=60003560008103604657600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +be8d399779cb2f1b616afb6174ba07ac61dd26cf04c3bea05f944e85666d81d4=6000356000811415604757600960086007600660056004600360026001d47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f41c0f6c76fc66275366fe14f2b8f2af35b0594a1b685ba5e78d1af61cdf98da=600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 9a38442cd0670da65eef3698a1898427c2ce78e75a1ab3e5c70b120b0b9191d0=600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -8e96e35d11f9f8532c879452f5db63f0895021bf129d206548a2c791629c4450=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +8e96e35d11f9f8532c879452f5db63f0895021bf129d206548a2c791629c4450=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 5c8ceecb04a87ff4b1c2b53ef865c0601829c40ae5f17653f39b3d936441a6e2=600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 dfb435ad82a9369f7453ba8f286b4b2e7499afd0b7ed7ef51eef7720c62a8ae6=600960086007600660056004600360026001d57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 4b6fde58d18bd57262e281bb7e9fb59ff191306e2fc0277d9e5f10a40c2091f8=600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -d3b66b44788668af78eccdbf58d84642ecff673e20b7502e1663cc431ab5d342=60003560008103604657600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +d3b66b44788668af78eccdbf58d84642ecff673e20b7502e1663cc431ab5d342=6000356000811415604757600960086007600660056004600360026001d57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 163945c5a9be31f3e018865aa765df7b14b682b3a9b9f0d021d4c29a7bb28f2a=600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2aee190bd85c6b513ea8f30f27da989327d6183e568c7f7ff991152eeb2c757c=600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -f7ad6f86da09b659cfc4d9947a7cac528976d6582509b69379eda8a21b998d7a=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +f7ad6f86da09b659cfc4d9947a7cac528976d6582509b69379eda8a21b998d7a=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 875f38a3db0ca95ee896d4b699bbf0ba9d25467a71c3572a1df57a7e07607741=600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b012e1e4d422e456b576d4cbe3f81675855c26125b190073924d2f8239080d5b=600960086007600660056004600360026001d67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe ae63b4287c7620c858ac5dc37c145397a6d69612673bcd9ef45f0cdb0e7a8d17=600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -64def6d894038ace4d29e4560133253a9dc739a4e008b598d12a6fd6e3236429=60003560008103604657600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +64def6d894038ace4d29e4560133253a9dc739a4e008b598d12a6fd6e3236429=6000356000811415604757600960086007600660056004600360026001d67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f4ef7077431710006a2b764b801578dcd027e2b86a6358bab4e486c92ef4685a=600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 775f19d00e1080de5f07d6846e7b51e9929ab37f6a27b7084794ab1c0f715b3e=600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -16c4d61fce0ada82ed2ec4656ab3865f8cdeefa98c7f5bf9d3fd06d8871a9419=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +16c4d61fce0ada82ed2ec4656ab3865f8cdeefa98c7f5bf9d3fd06d8871a9419=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a824e8ac73e123c5e07e5e107d2eb7abd178559b577294885c757f2f076311a9=600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 c1329fe93858de8b770dcc1c7e52f7349ac7bdb8610a18207bd5ae13b341a07a=600960086007600660056004600360026001d77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe cf8c4842e4bb9ece4811336ab2c422087238a45367ba1c11e193d7346ae31065=600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -331e3b5c867cdd5aa20285b95f2398f78d0e5a68ec062acbbc89fc8286da3037=60003560008103604657600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +331e3b5c867cdd5aa20285b95f2398f78d0e5a68ec062acbbc89fc8286da3037=6000356000811415604757600960086007600660056004600360026001d77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 94a82bf0575a00c9163b91fef857f2cfff2ecbaddcef44ea7c2ce5b6b38d9d64=600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5c0cec19f2d3ae92bdce5b5654fd8bee8044611589caccc23399cb60a6464144=600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -405255f663538275a907425bdcdb797e029036741dda74a120b29d7149dbce63=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +405255f663538275a907425bdcdb797e029036741dda74a120b29d7149dbce63=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8f8f08994f5f89ac8a9cde63b2ea1d677be283ca214089c5e0cf38fe13f4db53=600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 323f0b237c36d5cea8ac5dcf452b5f85b7ae706d87f01d7acbc46109573b3192=600960086007600660056004600360026001d87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe b36eb463bfed34c5d90ddee6c1592d4e8f93c2600bb220228b2556981449d367=600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -08978ff8d624d9ecb06071d361315d2228da3686f03af064dccec557f1db11c0=60003560008103604657600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +08978ff8d624d9ecb06071d361315d2228da3686f03af064dccec557f1db11c0=6000356000811415604757600960086007600660056004600360026001d87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 6c36283664f46e81235d3afad69072c43635e31c46794fbb3474f28078eb5793=600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ac6d8178f43cd0a6d05514c5e3af50ce7ddd3333535fba9910632b863fd8bf43=600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c724c311074c9a2ee54976e99d4ae0ce19897de982f1b5187a9cac58c25bf716=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001d97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001d97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c724c311074c9a2ee54976e99d4ae0ce19897de982f1b5187a9cac58c25bf716=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001d97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001d97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 69ec86bbdd4ade4070a50f6872983f5b59ae4333942d075b96995cbc94568e65=600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 ec0cd2b30d45a55c363acd904e6dcde544e5cd7eea4309392e9911f45e33007a=600960086007600660056004600360026001d97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 30bd6becf598597a96536d8eed93f9ef5644fb05954af3fdd072867adebbe13b=600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8d6322ba141319d9776813a3655c5f299ed3fd2fe1eae15948be78c79d4a0738=60003560008103604657600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8d6322ba141319d9776813a3655c5f299ed3fd2fe1eae15948be78c79d4a0738=6000356000811415604757600960086007600660056004600360026001d97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9458b6fd43c02f02f8542d869d0834b1f04e27c4fae4624584e7ff5b4fc79052=600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 59b9f014a87bf7838def2dfcd331d91b7a0915ae0db03002c81d932ac5f15f3f=600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -3f9c76d4bbfe55059fe39bae69dbef405332254451e1d7a1c7c9de151e2a8b01=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001da7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001da7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +3f9c76d4bbfe55059fe39bae69dbef405332254451e1d7a1c7c9de151e2a8b01=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001da7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001da7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 65d8dc667146b84ee62eb1fcf2694a76dd31a27b08bc00d70407974d47ccff50=600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 fca911db6adcd2fa48c069a8353858eb2955e951b3b75157b20ed2e03846ee82=600960086007600660056004600360026001da7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 8df84a49644c995eb18520a8c5230a2d024963dc265b89ae2324a536d81147d3=600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -870634eae2549eee081ca5f11660282ef4f8069ccf71f29afbc9fe6cd6ae7da5=60003560008103604657600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +870634eae2549eee081ca5f11660282ef4f8069ccf71f29afbc9fe6cd6ae7da5=6000356000811415604757600960086007600660056004600360026001da7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f631b07b0a7264219a1cc041fac7ceb62d22bb65ea09d6fc5700beca11e37d9f=600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 b16bf31ae1d6b8fa9e718acf1fb557be4eb770c6775bc2ee0932d86708ce6099=600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e8c593b5498e8afc393365076b80fe4770005e308197bfa5b323da1a66c0e150=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001db7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001db7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e8c593b5498e8afc393365076b80fe4770005e308197bfa5b323da1a66c0e150=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001db7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001db7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 c2a78dda9a8c7eb48f529d3e449d2d8b788e05265fd839764756e2c2076607e0=600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 bd03b9dbe76b449ab5fe33f92b39d9ea5a8c6a16d2c6caf2a380b1e902a80415=600960086007600660056004600360026001db7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 360a00f371f04b54bbfe13be05b8788c3e59ecfaa6881bc5e910b79c52a66307=600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -97a2c48b39d7d3a8f624dc8ce0181d677e218139d94caa6a8ae82ecc4cdab09c=60003560008103604657600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +97a2c48b39d7d3a8f624dc8ce0181d677e218139d94caa6a8ae82ecc4cdab09c=6000356000811415604757600960086007600660056004600360026001db7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 cbb0cf3fbb3f5c80bc9096e3928144501943c2feabab7ff0a3a2bb9eac5bceb5=600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 71c068967993c00134b8538ed23f2b6486441267f31e0a92e0e25b3810e81497=600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -fb7689fd218372578e00ff151d993cb0ce2b792bc3acb9e37a59f55803ae4503=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001dc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001dc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +fb7689fd218372578e00ff151d993cb0ce2b792bc3acb9e37a59f55803ae4503=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001dc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001dc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 e8b398e970686741ad54f51190189e1a5ded585f482a2c2f4a697657033255de=600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 7b370d0bca923d09f516af5a322472733de1589ed6ee37b1bc73c487f425b9b9=600960086007600660056004600360026001dc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe cfd246eac675a4ceecd8074c3e5583c1990f9fcf2b6d130572c1f0907259b360=600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -b781132f17c619b2ccd714cc1622704e74ee10935fea39cb439d9415e12dfe57=60003560008103604657600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +b781132f17c619b2ccd714cc1622704e74ee10935fea39cb439d9415e12dfe57=6000356000811415604757600960086007600660056004600360026001dc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 e6c8c72aa6f08fc6db5875486d607500fe965e04ee25e73df35785e576978995=600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ab28dbd529d23d84f896551e629a1915612e0745710de40eaebea1aefbd4b014=600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -160cf541e6977d5a09a2c467fbfc2e629830f54ad1b8a4c91489eb25c930b7db=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001dd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001dd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +160cf541e6977d5a09a2c467fbfc2e629830f54ad1b8a4c91489eb25c930b7db=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001dd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001dd7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 2ea73f874cd7182e0b5eff43404d91593e05b89bd5db0752a0452c8586146ed0=600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b85dfb52a17799294dd49d478e9e9297de19b1b14aa7420c7bb82ed53379f2ef=600960086007600660056004600360026001dd7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 8d86480db10dd96397832298544f8bdeb3007d321358b2f0aaaaab18939389a6=600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -9554b5e01a9a9f64a9b2f671630d836c3ce772d052b45d89b73fd098b8e4956b=60003560008103604657600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +9554b5e01a9a9f64a9b2f671630d836c3ce772d052b45d89b73fd098b8e4956b=6000356000811415604757600960086007600660056004600360026001dd7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 ae45994ab69564b9f752678823f17108f35b7c43d1ecc3c79e73d13955495deb=600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f8347065d449af9ab723ebf487760effac17d0a688f7d2d692ae4b1083d6087c=600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -fc3b1f81b4101c234f757b02963c76e321e1a19c86313f4a37c2729f36f96917=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001de7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001de7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +fc3b1f81b4101c234f757b02963c76e321e1a19c86313f4a37c2729f36f96917=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001de7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001de7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 c98b11cb7ff2d2c263c6071e3aef3949e61fd49135c9c702b5f97cfa4868b6f9=600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 99b152ba3596c620cfb81f360a2f1f13a3b67e8f79e407e04ec7b120278054e0=600960086007600660056004600360026001de7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 894f7d896c6f3f97aa74475659106e083c12f1c9485b47ba2a5a46b914750377=600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -197ace0677b5717dbe9bbb38a007d4f3d9812825b88e9a5d26d3bc6c217120e6=60003560008103604657600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +197ace0677b5717dbe9bbb38a007d4f3d9812825b88e9a5d26d3bc6c217120e6=6000356000811415604757600960086007600660056004600360026001de7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 978d1bb072c242655c64bd67200292aaea8a905e434635e1ed8f7ae9b89db82e=600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 61488411be39d9c3e1e0f15dc89143aaa78839f44d32f7e9e003bd71e87c2402=600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d6466f2f27d8ca3e9b3476113929d47bff8e5f2a00a660c80f3caa990ece0cd3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001df7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001df7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d6466f2f27d8ca3e9b3476113929d47bff8e5f2a00a660c80f3caa990ece0cd3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001df7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001df7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 d8c5bbd4c907b6331666081e9482c1c0141adce57f2a250e86ae4052f79f4aec=600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 850f5e5daba158cac9a20182ac89b09b1776df7dcf2201a5ff99e176ae70885d=600960086007600660056004600360026001df7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe b585478be2d5a7a3f172740d15bdd195936eec002036b56c44fa417a42da7406=600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -c88490b7609917a71bd76632e9201eec743796779723888aa6223d47f4404568=60003560008103604657600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +c88490b7609917a71bd76632e9201eec743796779723888aa6223d47f4404568=6000356000811415604757600960086007600660056004600360026001df7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 50d02a31714a13bad96ed7cbde3f5a7a50f12d568b29388904605f5671ed9c50=600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 c062216b1dc2fc8721c9c45646301694a0587b25a9fd9503f1b02a292fc86a1d=600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -b52a33d8d4afda44273bff7efec552c32ec14abc6513da8f23aedd5bb694f58c=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +b52a33d8d4afda44273bff7efec552c32ec14abc6513da8f23aedd5bb694f58c=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e07fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 0b920f1fe84b8c374a1ab93bf9aa760ae7c6806e0e2c6108f805561135365f66=600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 a2d670b4640142e018a6bd97b67b4a224d1e2cfd9d83ffca7323f1d7427760c2=600960086007600660056004600360026001e07fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 71170857b67aa7ce3c99da25de12b434b19462d52c8a3869bac0131d8252f5dc=600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -838dff6d3389cc17980a9c4a11de3e5c7391e8123c802f36008101d92e2a008b=60003560008103604657600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +838dff6d3389cc17980a9c4a11de3e5c7391e8123c802f36008101d92e2a008b=6000356000811415604757600960086007600660056004600360026001e07fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9e712e19129b8d66e24b17d1ffc677ab6c383bdad01e9082ce2c14d52e6a7076=600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e70105ebd0e122c5ef776e26d866cde52530a8c006e3295527f3deab717c1e66=600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -d8fdc37daa1e640c784d5401d6d0ca8e7de0cc2e4b29aa166df5ace2353ce82b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +d8fdc37daa1e640c784d5401d6d0ca8e7de0cc2e4b29aa166df5ace2353ce82b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e17fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 15181965c3c5ef7cb70238bd725622c8fbc4377cf46f839fc1259b065d9250fc=600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 358c91b529a4ecebb28364ec1f8d99613fb9efdbf0872f1958d226e4a860912d=600960086007600660056004600360026001e17fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 918ac15c8f7a5083d26993a83325ec98a4b16de9aa6a0215837275a050c6205f=600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -147142e2be4899fdd8ff9959236d1abac1e0033ed7c87b43e64ef73dcb86226b=60003560008103604657600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +147142e2be4899fdd8ff9959236d1abac1e0033ed7c87b43e64ef73dcb86226b=6000356000811415604757600960086007600660056004600360026001e17fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 d8b9606ab675ee115b0e60b04773f5d4a2df97c5eb99a443419fc6b3e1b2e474=600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e6ce16ceb898cfa9bbc0cba76df7cc00535795959f08a5eb0c02c9fce0ea34fc=600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -1d996539b54dc4ceb0bc68671b905a148681459bbde92ba5e9e3c1c8020a407d=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +1d996539b54dc4ceb0bc68671b905a148681459bbde92ba5e9e3c1c8020a407d=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e27fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f43f03e7ed78f6e2bfb5a70c6ade85dadf46d6c91afe7e60b2272df4e4aab3ca=600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 748ff30f8c474d41e87de746de6037d7d9d826eca2b7ecfa80c98fc8e6466b1c=600960086007600660056004600360026001e27fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 90f9c8ed5b164c21fe987d8145eba63e508302a173df32caf5bc8a463fceda63=600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8c4e34bc2e6dc2f06a18b86f33ff5fd536cd7ce3f50493b5efc56f91e63b3ad2=60003560008103604657600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8c4e34bc2e6dc2f06a18b86f33ff5fd536cd7ce3f50493b5efc56f91e63b3ad2=6000356000811415604757600960086007600660056004600360026001e27fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 2ef23e24840908e28f272d4c7f173528c3570840129b69c795879c61310015ac=600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2a5ebcc50b0e976a4ab894984c5a6dae8b8ea71ef0625047d15c4cdbb7866be6=600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -5d948400df239177e455905eba8f51f32b0f5e5e69b68e244b8fcffa8703145c=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +5d948400df239177e455905eba8f51f32b0f5e5e69b68e244b8fcffa8703145c=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e37fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 7184f958970c18d7adfb10b2ec2b601452aa1131c2b21ec877b0c5ebd7f51633=600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 7804a58e973d93c54d03faedc926895199fbfd19e9461eb229e0da36afa3042d=600960086007600660056004600360026001e37fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 1a63c5fdb5fae8d3416f1243245bf1231abfb8c558d8509b76d915292c27f6b9=600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -4d248672a92e38f633896e9e5bf15c772fa582fe5ca04dbc81d771a60bed395f=60003560008103604657600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +4d248672a92e38f633896e9e5bf15c772fa582fe5ca04dbc81d771a60bed395f=6000356000811415604757600960086007600660056004600360026001e37fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 f4b9860f730ac0ce4cdd628b4a68d77127144da2d6336f249cd0e1028b331958=600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 004d869f75d3113eb4b1a8b5c3282f1ccf2f42d15f9708bb95ef48907fc696db=600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -8fab11955a49591336a0bce44ce64f1aa3e2ed52e8220b54a112d7bb2314126b=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +8fab11955a49591336a0bce44ce64f1aa3e2ed52e8220b54a112d7bb2314126b=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e47fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 1c11ba4de8f65fd6ebf6bbd4701233fff32babd9598a55a7c2274e6aff3b0bc2=600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 7262317bcd650546789641e6af1fae56fee788a8e5eb01a91073b0038a8ceadb=600960086007600660056004600360026001e47fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c940dcf747770c6769d1247f2f1c4a24b376efff10320068098674d6bc55348f=600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -a60757a515fed7e4001a6c80bf5eb79662a3e2f790b5d218ace612848892d24d=60003560008103604657600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +a60757a515fed7e4001a6c80bf5eb79662a3e2f790b5d218ace612848892d24d=6000356000811415604757600960086007600660056004600360026001e47fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 bd43068cdf178c5141677a7dc456fe49fdd5542aa6015f895c0cae8dcfe05218=600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f949f0e895164d46b43e1fd7e6891f8487c3ba0f76e2f425586c975fee6bf23c=600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -c204db0c59faaea7e9626de3a05dc08fd7c77bbf3f912264526c4a202f7df095=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +c204db0c59faaea7e9626de3a05dc08fd7c77bbf3f912264526c4a202f7df095=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e57fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 92b4f61420d40e50c74aeea4079577f930e1fe9c93c6ff3b6917c0a63f60002a=600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 a01cdfb37dfffb72a91d601b507b85817df2b9a0e326121e61f6b0c65cbb1ca3=600960086007600660056004600360026001e57fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe bb21e9c890ae5f2f18be121ca55d570705aa54ce039be0f02e8e95414a7ee777=600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -b14413ae274483b2b02dd1b409a7648069eb31f13cff3689197ecc2e7947104a=60003560008103604657600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +b14413ae274483b2b02dd1b409a7648069eb31f13cff3689197ecc2e7947104a=6000356000811415604757600960086007600660056004600360026001e57fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 448dee1cdc38e696009657272efa1e2e1381bba0846b564600d465de9fad0723=600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2e738888b00adbf0f721a9ada9299e58cbc96558f847d1234d1261932abf02cf=600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -f7dfd3c51bd9bcb2ca1bdcf7bdc99d9b3de7c6962f409b46b98ad12202db9746=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +f7dfd3c51bd9bcb2ca1bdcf7bdc99d9b3de7c6962f409b46b98ad12202db9746=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 6bfc8ec98f64c2587317236f1510fbb5355a1a92fa07883db7d3f536de27a638=600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 cf403ca4444fb4d137e849c9171585d46b87d99ec538275f7e66710e6c1ffc34=600960086007600660056004600360026001e67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 770bd70777d6d9f6da72762abeccffc85c6ab6756e160e02712222e20306deac=600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -97c18561f3dcd2620892b7275d3db5ffd49143df436c750cf87a8ecbf4bf53fa=60003560008103604657600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +97c18561f3dcd2620892b7275d3db5ffd49143df436c750cf87a8ecbf4bf53fa=6000356000811415604757600960086007600660056004600360026001e67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 0b24158a59c86d19c78373b88e3161ebcc1c6a0e04c549b49701cd0b0e1c5737=600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 6485b4eb21ede9bd055ea05483bdaa33254cd92105e2308e9d18fce8338d2433=600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ee071cdda683c7ceff8b9b83f1481c2180b9c3f8571cca56b91c95017b1a2116=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ee071cdda683c7ceff8b9b83f1481c2180b9c3f8571cca56b91c95017b1a2116=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 4c7afa2c891225aa4c8c986c82073f08539b48e7a57ea81b79296f9eae780e0b=600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 12ac3f9b1eb1e2413e67bee48e812532cc9eb0173f52da644fc378d5d8a95e0c=600960086007600660056004600360026001e77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 30071e8db62321fc32b490e741b8fc5536f612665632c320144a36b9196a3e77=600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -02573bc0c5143d90436c8ff66ebc7f621436a6cc40278f9d9460059247811a78=60003560008103604657600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +02573bc0c5143d90436c8ff66ebc7f621436a6cc40278f9d9460059247811a78=6000356000811415604757600960086007600660056004600360026001e77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 e2378fa0cb856ee48b09c7e8b0db9f52123bae9dabff49eeab4bf212166dbfd7=600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f1cd14bae66897b416e5e20ed1b50a21f7e8ee07441324ba8faa2e1bc8428d7a=600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -4c5d6782a96a8855f216b981439480744a61cb8277cd958f7440dca653b21b33=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +4c5d6782a96a8855f216b981439480744a61cb8277cd958f7440dca653b21b33=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 741179d363ca301ff2c65d4f13db04d42bdc3bf59ea5dc5e4dac1218d6a98a58=600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3c2b6934acde64f6d8588a20304a2ae2a13a6a65316ceb0dd7fb96839707a56b=600960086007600660056004600360026001e87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe be0ebce8b105dbbbbbead7c935065267c5567badd5a816c94191e634bf341887=600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -1666550ed444b24d7984ecd6191d558e7a52352344ea846b61ef4eb81ee7d194=60003560008103604657600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +1666550ed444b24d7984ecd6191d558e7a52352344ea846b61ef4eb81ee7d194=6000356000811415604757600960086007600660056004600360026001e87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 fd51cabe84e080eee626fb7ff99e5e5b54254ec8a5ca28417d30e576c4f51b3a=600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 f52593d3ce08e889d02ca234c7fe21a3222660b4d8eb0d7398963e896dffaf18=600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ac2a746cfe8a2238a189ca6bca3710601a315749b5c1e554ece549119658cfe3=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001e97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001e97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ac2a746cfe8a2238a189ca6bca3710601a315749b5c1e554ece549119658cfe3=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001e97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001e97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8cba75cd4b78afff97003cd8758eba1775b5b4809b42bfa0d17ccf460f458d09=600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 83b9da2d97405bb336b9d9e452a1e4cd5b66475bc7cf554a1a0fd76a818e8173=600960086007600660056004600360026001e97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c3eb6c19c606f2e44d7a1b6446bdb49671b49b6de924274929c866a279cd588c=600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -508cb9e9c724f7c54026bf7a66bb3f86b6ee58f3d630f5d52949ab17edcfbcb6=60003560008103604657600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +508cb9e9c724f7c54026bf7a66bb3f86b6ee58f3d630f5d52949ab17edcfbcb6=6000356000811415604757600960086007600660056004600360026001e97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 fc5416739dbe5bc410d5c09a131838d69f2d872a199d8b72076fcb81cb0b0385=600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 7c5ccb1941125ae95b92319bfc5075c48bb9ab7be68b080da30616aafa66efb7=600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -1f1751da9715f59708a3bc6aedca352318984206f05550f900d15f58caecd3e2=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ea7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ea7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +1f1751da9715f59708a3bc6aedca352318984206f05550f900d15f58caecd3e2=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ea7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ea7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 f675e7d0054ac2a9fd2d4041b18dad38a4dfee33b9548ef9ac3ea7dc213225fd=600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 6fc248e5fcf6149b241e47474249f34563d0615515edfdd5f009eb89a65261be=600960086007600660056004600360026001ea7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 2d2de327c12b768da69a87030c7570e2a34fa56bb9b2c992a51018a5930730b7=600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -790d409dd506e4483d1c95bdcceb0ffe7d377bd248c1024981e1eb580a074745=60003560008103604657600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +790d409dd506e4483d1c95bdcceb0ffe7d377bd248c1024981e1eb580a074745=6000356000811415604757600960086007600660056004600360026001ea7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 2991645d30d0f81333430b4feee3c094a02487997ed2e3c9ffe1aff72ca2e03c=600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 5ad97103143eb047e9a9165cc1f11b82ecefce78db8858e3e578b9ac9999491e=600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -749aca47d178d05e3cf31550643c9ea9ec3cfc7ebb3faaaab7999a7a03616d04=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001eb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001eb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +749aca47d178d05e3cf31550643c9ea9ec3cfc7ebb3faaaab7999a7a03616d04=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001eb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001eb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 73cfbd20fb20381794fba4875c1ebe2a19f8847325bdca681a2771b885f961e3=600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 0c831cd6fac65d3e335439819f6e11e95cf63d5a55580c146ec1557ab788f918=600960086007600660056004600360026001eb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 2487f9d3459e086b2088b8fdabd90d263cf7f2321a596b53464400cacbdce974=600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -bf43887b8ccffedf3b7ad7612936bacf07c5a3ccc9cb833a50a3762c9eb92edd=60003560008103604657600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +bf43887b8ccffedf3b7ad7612936bacf07c5a3ccc9cb833a50a3762c9eb92edd=6000356000811415604757600960086007600660056004600360026001eb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 4422cf00319d3c6a5c5e443a8f19a50ef85e8e599ba92fd911afda95f996c533=600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 c99c258df1e50fbd0ad72e7b1adce397df49b9325767ed2b9981d8dff580a424=600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -dac939bea3b32e80426f9b4c1a549c752872c8ddd8c0cf7d2948daab6136c466=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ec7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ec7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +dac939bea3b32e80426f9b4c1a549c752872c8ddd8c0cf7d2948daab6136c466=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ec7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ec7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 c92b7f7cf758c418b11eee606cc18a463b0090d40792e9df7518915ef1d5e5e4=600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 b05952efd7dc44559e180dcd9f8258075ea0bc6b7c358e600ec13b6581919b9c=600960086007600660056004600360026001ec7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe a0f6909df33c00736528b1959c7e34244e7e3043297e09678bdcd7e644929ec9=600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -16af98e3251ea8b8e3602e4836e4fabcc6bf77a778c82049807d17b3fdf35a75=60003560008103604657600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +16af98e3251ea8b8e3602e4836e4fabcc6bf77a778c82049807d17b3fdf35a75=6000356000811415604757600960086007600660056004600360026001ec7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 9b454404772226a5db6f7f798e465a0dcd47accf73f5d9e5fab44731d6052d51=600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 e679d4e17ab1e726c6eb12146eb5dac927307db1e9e5083af9b12cc0fb1f5c70=600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -94826e1a45103e831581ac5368ffaa27627b0b466f8dc027e59eae2e2dcdeb22=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ed7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ed7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +94826e1a45103e831581ac5368ffaa27627b0b466f8dc027e59eae2e2dcdeb22=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ed7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ed7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 d557e90865d1307627e76f21aa7298c39cd0f612ea13feac9f7b540cf2df1fcf=600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 08877d272eb0c04b7bcf9fdd68f74cbcd1c9e0888aeaba02898ca2ce87bf6503=600960086007600660056004600360026001ed7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe c0259ad40b8922acb3889dac1db324d0c28379ef4d375cbd48a3628359118269=600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -fac9b9c7698a12627883df0e362f966cd83abb95aa505594d7faabc40a2b4c41=60003560008103604657600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +fac9b9c7698a12627883df0e362f966cd83abb95aa505594d7faabc40a2b4c41=6000356000811415604757600960086007600660056004600360026001ed7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 8a18d4a7a9184f5cf6a5c3e08b77080ccc314000dbe68c5e47be5c0babb8c832=600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 200e26eb56e6656f0092ab68376777202054401a66caa6936e805ca5863af2e2=600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -5c77cf8e7cd77ecfc8e53ebd4a8801e3463e9f31462faa0f30fae5487b019f54=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ee7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ee7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +5c77cf8e7cd77ecfc8e53ebd4a8801e3463e9f31462faa0f30fae5487b019f54=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ee7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ee7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 1b8526f4a0eb15e80297bc3266c5d47d6dbf8e446f4cc25fc1012324509d29e5=600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 86a08195a2cd38e59ed66b1018861c7c253db9be50f0eccd8ce98c1e28fdc9a0=600960086007600660056004600360026001ee7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 0e8d12772c6b9ea24d72b536f7e173abc5ff5690bd03db17bf8a2bc2c18b4856=600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -d6afcfd9d082830fc0c0e212c9c6ff9347b63203119217ace3e76f3fcd803075=60003560008103604657600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +d6afcfd9d082830fc0c0e212c9c6ff9347b63203119217ace3e76f3fcd803075=6000356000811415604757600960086007600660056004600360026001ee7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 4188def3c908f821e7eeeda474e26783a020985f72f51d460ce6e56a8c047382=600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 ea674664bb589f3b0bd3ab158f8b3190fe86ad034e9f3b74cb96db0320111057=600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -ab098c91a13fa3ac0d7825c39a892b40b660fc1a26c26692d016d9e556ff7b7d=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001ef7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001ef7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +ab098c91a13fa3ac0d7825c39a892b40b660fc1a26c26692d016d9e556ff7b7d=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001ef7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001ef7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 a130730ce2d9bb64aad176f5548267d617949d578cc6d10708f72dd0455a6884=600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 528551b0bfdbe14e3d782f97911a7928ec8e37396374037720cafc1818e16a05=600960086007600660056004600360026001ef7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 2c27eda63c29e0eab08260e36aacfadfc6ceb28129cf27818ae300f76a213bfc=600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -54823c00c84f087d687ad203696c739d49e1a2b9e1fd265b115c1292011f79fb=60003560008103604657600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +54823c00c84f087d687ad203696c739d49e1a2b9e1fd265b115c1292011f79fb=6000356000811415604757600960086007600660056004600360026001ef7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 130e8f17c85252e3e5b4211fe7658c031a3e7928f8f82be4a9cdcf22036d0771=600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 149217604850d2db398de728ed7e92ac81a736ef24af6b728e3efe48c6f5580e=600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -e075b85082356d2adac0e23604d8fa75476e55156fa1ff51057d10d809b28275=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001f67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001f67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +e075b85082356d2adac0e23604d8fa75476e55156fa1ff51057d10d809b28275=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001f67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001f67fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 8e06cc3f38e5075be9fa28e8515a93cc044db9ff0d413857ab63090f1c560054=600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 551460d3811a5057532721ddbe687ae86e68e64195ba9f1a0ba6de1ffa8cb2c3=600960086007600660056004600360026001f67fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 92e1a3010fb46ff1fb92d3d596064909d890d5f07877e143d912df5fe84e3c2f=600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -efca004e21c714ff1882b8704340b5ca514f095967aeeb63a1c1eb9b227cc223=60003560008103604657600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +efca004e21c714ff1882b8704340b5ca514f095967aeeb63a1c1eb9b227cc223=6000356000811415604757600960086007600660056004600360026001f67fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 66626bd408b53255151083f06eda987d818c85248fc091fa5f6f987b1437bce5=600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 48f7d28dca8a60ecf9c7390e24c109fa9cbac35fc25903c9961df7e0f13162ca=600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -a0886f328f015a1288ae2fa74ad076ef06b4a54ecba42e77f5b7d4ead12fee3d=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001f77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001f77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +a0886f328f015a1288ae2fa74ad076ef06b4a54ecba42e77f5b7d4ead12fee3d=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001f77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001f77fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 86b2e0b1d3a7abbe8892ece62b8a3b3ac04dac2a42dab2238b4c4db47ecc54a8=600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 ac9b6e7eab17f4fb2c5ce550d16004ddc1dd585bd8f23f2efadddcb8faf62a32=600960086007600660056004600360026001f77fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe d1a5d7ad17bf02e2368bd1e326414a9d1db70f57d837232f0bc0bbb94474ea8e=600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -2fab2f4022d9e68b4c9bde400ec8444f2d0987f4f56e7e3829fecbf79ff680aa=60003560008103604657600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +2fab2f4022d9e68b4c9bde400ec8444f2d0987f4f56e7e3829fecbf79ff680aa=6000356000811415604757600960086007600660056004600360026001f77fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 ba34d1576787716f1d1351cbcfaa4a3f206d86cc8ba8256eb36fee0e43443a3a=600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 544f89ca28f35f4a7c4ba6b89918ff27f0173750045d58551fb9c756ad42e4d5=600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -732386382ebcf1e94fa88c27bc1ca78c34fede07f54b73d84f51036ca80f03a4=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001f87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001f87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +732386382ebcf1e94fa88c27bc1ca78c34fede07f54b73d84f51036ca80f03a4=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001f87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001f87fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 eaac45cae1c91ddc0cea84ecc42109eef7a432ec70bfe0ab310f5b6248c47b64=600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 7734e4759cf3f82530b97d76f06f0ec43a4ab2894ff0ee4733a6083a295b0894=600960086007600660056004600360026001f87fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 84de9c38859f423edceaaca6adfbd1bba371db979512238ed1990488c1eeaa2d=600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -3b66d4f3fe8ce9ff5ea2e29c8829dca24e231020e5cc843e41b6859a475b9fdf=60003560008103604657600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +3b66d4f3fe8ce9ff5ea2e29c8829dca24e231020e5cc843e41b6859a475b9fdf=6000356000811415604757600960086007600660056004600360026001f87fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 764a4ba331bf7ee3cc40136347fc0bfcbbf53a2c3bc6b96d7db777a4fd8de3c9=600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 380f19f02df7665b3bca3d4ea3307dd40ace2f8eb5e1e7148f6ab9581ecf2386=600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -72dcf1e1aa56c92cf038fe889da1b7822ffe1630233703b08b6384bcbf422dac=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001f97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001f97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +72dcf1e1aa56c92cf038fe889da1b7822ffe1630233703b08b6384bcbf422dac=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001f97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001f97fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 e0ab635835c12d40088b1bbba2810127fe547d24828b4f410c124d52365404da=600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 ed348aeb464344a017bb9cad3309f4d37c5bb3c6b316dfe930334f1df000ab11=600960086007600660056004600360026001f97fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe f71bd4bdb0866e72f6e47a2d83cf288b9f835d95f8f45a194e32e0efada535ca=600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -621388d59d36a339074b9d69c476be0f65475dce67601f723a9ba9b79b4fa608=60003560008103604657600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +621388d59d36a339074b9d69c476be0f65475dce67601f723a9ba9b79b4fa608=6000356000811415604757600960086007600660056004600360026001f97fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 0d8265dabeb6d9eb79896c42ee04c67afff9e48187d5adab68a4763a2a28faa9=600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 def56e3326695ace527958b3bf1a7976e8ad11b1ef353c7719b74c53bf114f4d=600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -9c0194fa50a9b8adf02dac6daf1181f8e873e5d5f9a4bc37ec6cb173fe6f84cb=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001fb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001fb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +9c0194fa50a9b8adf02dac6daf1181f8e873e5d5f9a4bc37ec6cb173fe6f84cb=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001fb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001fb7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 c8b6a7bb41353a21c229fdb76b587e903155597eb5d822459d9cbd71799c126e=600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 3ef1ec27d7ad72b7e812963d31b03d485ce148e671d4924f73b6eb268e9a01cb=600960086007600660056004600360026001fb7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 37c262381218dbef934dd5f7dc2a9f81a6cd63fdacd6e5c53586e2ba83d01746=600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -8b057a099f7b4d272da7a5208e6ab9450b9031dbbe3c2d18a90c2a8c59f5a613=60003560008103604657600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +8b057a099f7b4d272da7a5208e6ab9450b9031dbbe3c2d18a90c2a8c59f5a613=6000356000811415604757600960086007600660056004600360026001fb7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 b087d8d8964016028417a134fa6aaf6f7041883d435986a67edffc817471cb59=600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 2f2ed98d4ea262d50ad3c7e1400ed6d2462c7a4b05a71aeb0e6e780d132caa00=600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -7298454d03ba1e1a1cbf32f062e8c19b2026d0c00b91c2c2908597112acb974e=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001fc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001fc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +7298454d03ba1e1a1cbf32f062e8c19b2026d0c00b91c2c2908597112acb974e=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001fc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001fc7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 16513dc959b0a2b4a245e7608771a01e6eaa750ad6fa07a9c17ef6c4b7f09968=600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 1f0d48fd4212f0451bb29d193812636f7fee3642d8dfab2e9aeef817daeff580=600960086007600660056004600360026001fc7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe a6c29866c12943f819a2dc44a05ffcf8e1fa22a24589a38b14ce05e45f2cba69=600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -6e032b46774ee52a28b67cb147af38734a8fcbc4f2b0a84094eb4bededc590b9=60003560008103604657600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 +6e032b46774ee52a28b67cb147af38734a8fcbc4f2b0a84094eb4bededc590b9=6000356000811415604757600960086007600660056004600360026001fc7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 7004cff6a85e2c30fb2f711e0986d1eddb81a650c26c31f1ed4d5bd802bf93ab=600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516040526021603ff3 05f1cb0012e6f176881117d451b9b045f242be5dc419ac3e8c336bcec0be97c5=600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 -564733c13227d18244a0766222bb2a3098c3ba68e51c48dca39b7eef76927911=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101975760f281146101ab5760f481146101bf5760fa81146101d25761f1f181146101e55761f2f181146101fb5761f4f181146102115761faf181146102265761f1f2811461023b5761f2f281146102515761f4f281146102675761faf2811461027c5761f1f481146102915761f2f481146102a75761f4f481146102bd5761faf481146102d25761f1fa81146102e75761f2fa81146102fd5761f4fa81146103135761fafa81146103285760fd811461033d5760fe81146103da5760ff81146104795760f081146105175760f5811461053a5761f0f181146105605761f5f1811461058a5761f0f281146105b75761f5f281146105da5761f0f481146106005761f5f481146106225761f0fa81146106475761f5fa8114610670576460baccfa57811461069c5765bad0bad0bad06000526106b6565b600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526106b6565b602060008060008061ca115af195506106b6565b602060008060008061ca115af295506106b6565b6020600080600061ca115af495506106b6565b6020600080600061ca115afa95506106b6565b602060008060008063ca1100f15af195506106b6565b602060008060008063ca1100f15af295506106b6565b6020600080600063ca1100f15af495506106b6565b6020600080600063ca1100f15afa95506106b6565b602060008060008063ca1100f25af195506106b6565b602060008060008063ca1100f25af295506106b6565b6020600080600063ca1100f25af495506106b6565b6020600080600063ca1100f25afa95506106b6565b602060008060008063ca1100f45af195506106b6565b602060008060008063ca1100f45af295506106b6565b6020600080600063ca1100f45af495506106b6565b6020600080600063ca1100f45afa95506106b6565b602060008060008063ca1100fa5af195506106b6565b602060008060008063ca1100fa5af295506106b6565b6020600080600063ca1100fa5af495506106b6565b6020600080600063ca1100fa5afa95506106b6565b600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560008060008060006260bacc5af150600960086007600660056004600360026001fe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600054146103d557640badbadbad6000525b6106b6565b600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000806000806000620600066161a8f150600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461047457640badbadbad6000525b6106b6565b600960086007600660056004600360026001fe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600080600080600063deaddead5af150600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541461051257640badbadbad6000525b6106b6565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106b6565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af195506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af195506106b6565b8160008563c0dec0de3c81846000f094506020600080600080895af295506106b6565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af295506106b6565b8160008563c0dec0de3c81846000f0945060206000806000885af495506106b6565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af495506106b6565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa95506106b6565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa95506106b6565b6103ff6000526020600060206000806460baccfa575af195505b50846106c25760206000fd5b836106cd5760206000fd5b600051600055505050505050 +564733c13227d18244a0766222bb2a3098c3ba68e51c48dca39b7eef76927911=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101985760f281146101ae5760f481146101c45760fa81146101d85761f1f181146101ec5761f2f181146102045761f4f1811461021c5761faf181146102325761f1f281146102485761f2f281146102605761f4f281146102785761faf2811461028e5761f1f481146102a45761f2f481146102bc5761f4f481146102d45761faf481146102ea5761f1fa81146103005761f2fa81146103185761f4fa81146103305761fafa81146103465760fd811461035c5760fe81146103fd5760ff81146104a05760f081146105425760f581146105655761f0f1811461058b5761f5f181146105b75761f0f281146105e65761f5f2811461060b5761f0f481146106335761f5f481146106565761f0fa811461067c5761f5fa81146106a6576460baccfa5781146106d35765bad0bad0bad06000526106ee565b600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526106ee565b6020600060006000600061ca115af195506106ee565b6020600060006000600061ca115af295506106ee565b602060006000600061ca115af495506106ee565b602060006000600061ca115afa95506106ee565b6020600060006000600063ca1100f15af195506106ee565b6020600060006000600063ca1100f15af295506106ee565b602060006000600063ca1100f15af495506106ee565b602060006000600063ca1100f15afa95506106ee565b6020600060006000600063ca1100f25af195506106ee565b6020600060006000600063ca1100f25af295506106ee565b602060006000600063ca1100f25af495506106ee565b602060006000600063ca1100f25afa95506106ee565b6020600060006000600063ca1100f45af195506106ee565b6020600060006000600063ca1100f45af295506106ee565b602060006000600063ca1100f45af495506106ee565b602060006000600063ca1100f45afa95506106ee565b6020600060006000600063ca1100fa5af195506106ee565b6020600060006000600063ca1100fa5af295506106ee565b602060006000600063ca1100fa5af495506106ee565b602060006000600063ca1100fa5afa95506106ee565b600960086007600660056004600360026001fe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055600060006000600060006260bacc5af150600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000541415156103f857640badbadbad6000525b6106ee565b600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560006000600060006000620600066161a8f150600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561049b57640badbadbad6000525b6106ee565b600960086007600660056004600360026001fe7fdead60a7000000000000000000000000000000000000000000000000000000006000526000516000556000600060006000600063deaddead5af150600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005414151561053d57640badbadbad6000525b6106ee565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c6106ee565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c6106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af195506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af195506106ee565b8160008563c0dec0de3c81846000f0945060206000600060006000895af295506106ee565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af295506106ee565b8160008563c0dec0de3c81846000f094506020600060006000885af495506106ee565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af495506106ee565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa95506106ee565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa95506106ee565b6103ff600052602060006020600060006460baccfa575af195505b508415156106fc5760206000fd5b8315156107095760206000fd5b600051600055505050505050 346d6fad6b517c62f2b07bfbb66c2b902a2a033bbe2b4a7bb896b692420452b4=600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f3 294a7c35085c0947a909e2167712861b0fdbe14f9aff6b4e0197507ee784982c=600960086007600660056004600360026001fe7fdead60a700000000000000000000000000000000000000000000000000000000600052600051600055fe 3ff76d99e731d79141b5d3a53a252a8b009785a86e59d86e620799c55ef6b27c=600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260005160005560206000fd -972da93271a848f9a5ee60cc17d73c56ff8db8f01f50a3e0b413f87591e70f89=60003560008103604657600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b600181036000526020600060206000806460baccfa575af160675760206000fd5b60206000f3 -0fe574972cc9c19750b1f10dd6f2d9bdc5b92b04935875b2716fc6a456d18934=610200600080f0600055 -cd9646219770ab10d99b25d29215d8ef36dab77db51b67cf814e6a6dd3e2f560=615a17610200600080f5600055 +972da93271a848f9a5ee60cc17d73c56ff8db8f01f50a3e0b413f87591e70f89=6000356000811415604757600960086007600660056004600360026001fe7fdead60a70000000000000000000000000000000000000000000000000000000060005260206000f35b60018103600052602060006020600060006460baccfa575af11515606b5760206000fd5b60206000f350 +0fe574972cc9c19750b1f10dd6f2d9bdc5b92b04935875b2716fc6a456d18934=61020060006000f0600055 +cd9646219770ab10d99b25d29215d8ef36dab77db51b67cf814e6a6dd3e2f560=615a1761020060006000f5600055 a8b8864fb681a19ccd2c165422f515b7f880ebe72c9e7763e395e54ef9520d2c=63deadbeef6000526101006000f3 74abd0b6773d7e56910bffd51015a816f1be85889f54357e0b94cc8da40fccc9=61beef5150 813aeb718ccb8cccdd9ff70ff394092a1012f072db8fca7637732cf38e31888d=60ff61beef52 6f4cf8175e4d21d167dfe5839411e2a9291a3d57060ebfdc79c640898daa74df=60ff61beef53 -c768c173e76aa9afafc358f1faa7a441e93dc31af52f01496d7743b21d8d9bf0=60243560443560043562c0de000160005b60008103602d5760008060008060008689f1905082840193506010565b82840360005550505050 -43a2044718bbc63caf58b8787e580d53758357db8f9a1dd83f6dec4fd5ebda3a=600035600052600036600080f560005560018055 -b3ae2ca19746076634f6ce2073cefb64cdc7ae3dd306639840eebdb9ea882f00=6160006000f3 -c44968378b56fe928db69677e9f50d18fdf6ae558b6afa25ecb473ab38558d23=6160016000f3 -58cb5fb86ad9d15449738047d3b636c8da84305fc0085d159588788c8ed9cb49=60003560005236600080f060005560018055 -52227e17d7647fe54dafe44b4deb62e226a5128df5abeb56b567d38dad4d665a=600035600052600036600080f5600055 -340145cf7877773c55440eb898245cda7ff08bffbb771df78ba3304b528ec4c1=600435803b80600080843c600081600080f560008103601a57fe5b505050 -5e89e098fa8a48e4074af88f6823d5ce6305599a4ba824c41d6f249a2a45c363=600160005560018055600060015560016000f3 -c0553b477805522c5df52fb777795c449f563514238aa02af2bff31c12129e9f=60016000556001805560006001556113886000f3 -64f9d48dbb03e233b564cffb000d25d46d619bf7ead017c3a60da12bbda05e92=6001600055600180556000600155fe -4e8170cad07e738c37d8081a5043b7dda9218af13e3e8c2d8cc933f92056030e=60016000556000806000806000620c0dea5af15060016000f3 -aa22e6199d06e6084cda614c3a3db0be54f5f87f362de868f596d2b68148969c=60016000556000806000806000620c0dea5af1506113886000f3 -cc9309c1b6cb2faea24cca4c16c568792e9ba7bd09cef2a913672bd0c38382d6=60016000556000806000806000620c0dea5af150fe -60948fb40224c78fd3a4c9aaa7e7a04973a6f7e7e78805b49dfbf819b847ea08=600160005560018055600080600080620c0dea5af45060016000f3 -a4eafe227ee9964f46af2519ea377ae296a117b84a91a54fde4f4a321d009830=600160005560018055600080600080620c0dea5af4506113886000f3 -3490e27dac61dd1c08c41a6d5fd3d6df2d5c053660def96def65826e1d059792=600160005560018055600080600080620c0dea5af450fe -f82e343e47b2a2164551d322270159a4d6f2e32443eee96e671d40af31792568=6001600055600180556000806000806000620c0dea5af25060016000f3 -6d1cf3d28163e44c11833d12ddb720f6fa12983d9989d57560375cbccc615fcc=6001600055600180556000806000806000620c0dea5af2506113886000f3 -93a4c5e642c58f6ea90ef828723fdacca3b8254909dc7de50b54a035add60ebd=6001600055600180556000806000806000620c0dea5af250fe -13febad19db39c352c37a194221a3658ab3c1d4fc7188ff7e76b4784b62ef8ca=60016000556000806000806000620c0ded5af15060016000f3 -ca690331276298ad3f041bf742be14b44d3b308f90925e5ccc93c5a9b6c0aefd=60016000556000806000806000620c0ded5af1506113886000f3 -bdd7b053de3ae2d9398c43459cb70dd456a242b868144cdf53c4cd94f4b1d471=60016000556000806000806000620c0ded5af150fe -adff105dfff0c5647ec1ce6fc08d2083f927ca29e76e12f9f206a88a49724331=60016000556000806000806000620c0de05af15060016000f3 -68f65e37716676a50230ef8fe1b50f7ae45b9a35c28f893fe6f452ee27c1c85c=60016000556000806000806000620c0de05af1506113886000f3 -6a819c53a9ea47952ca7a953489d5625d102ea77122cf21e7376b6fb99db8872=60016000556000806000806000620c0de05af150fe -36c8e5e4d13fb10e4f3b50768b298da7ed47dd6dc82e68b555184cd0c879345b=6001600055600180556000600155620c0de1803b80600080843c80600080f0506001808201f3 -047d5aaf086bdd6f55cdcc7b5ca8f1de1f7321f7fb8f03ee6dc1b6833d9b00fa=6001600055600180556000600155620c0de1803b80600080843c80600080f05061138860018201f3 -53adb60340f14943f224f428f6d3a8eb7edc14b89fb5b459eba8e1549ea187a1=6001600055600180556000600155620c0de1803b80600080843c80600080f050fe -91bbbde20fcd7e34727b852e501b73199c4273b1b32933dfc335a18e8e8e1f8a=6001600055600180556000600155620c0de1803b80600080843c600081600080f5506001808201f3 -543016ad470d6c160504dc6c9c8ddf08b16707bde3f564c397c001a8ddeba5b6=6001600055600180556000600155620c0de1803b80600080843c600081600080f55061138860018201f3 -47916ef90b042f3a5106cff87fc7a949b0f1d40e763cfcd201ec85b4bfde6ec8=6001600055600180556000600155620c0de1803b80600080843c600081600080f550fe -8648b214afb7430e364eba9298aef2f4cf789dfe3c10b7169d60aca559d4db65=6000600155 -80ab328c7bf9ff6ec231b37fd3a29be9a4a52ce75a9403ac1f1d3dfa4c12e8b6=32ff -d788f00379736afa7b39a7532465cb8ea82a12dd35d61daec41b81356fda4cc2=60ff60005260206000a060fa60206000a160fb60fa60206000a260fc60fb60fa60206000a360fd60fc60fb60fa60206000a4 -23a0e63111b844c94ad18cf0e41bce1a67fa8635ec21efaf18bc6014c29f084a=60016000556000805560016000f3 -50ac9394e4391fc0702cfc7b594d452128fbda9f4060d0f949916d03701fcc4d=60003560005236600080f0600055 -8f2b325bc960e0b2589c62f03544cb60df9ff0743d658cd3b2531de5b60d4036=6000356000545560016000540160005500 -2ab24936454b2c8365281adf6aa1abbeab4c3834a3470510287a934d1f9fd054=60068061004c610100396102005260db8061005260003961022052600160043514603757615a17610200516101000160006000f56045565b610200516101000160006000f05b6102405200fe60ff60005500610100610100610100395861026052600060006020610260600061da7a62fffffff1503061026052600060006020610260600061da7a62fffffff1503861026052600060006020610260600061da7a62fffffff150303b61026052600060006020610260600061da7a62fffffff15060206000610100396101005161026052600060006020610260600061da7a62fffffff15060206000610100303c6101005161026052600060006020610260600061da7a62fffffff1505861026052600060006020610260600061da7a62fffffff1506101003803610100f300 -8fe0d0b35be498ea58c02e2f3bfd06f7ff8c08eb81f04115affacd68520f5ee1=601d60005500 -6bc0f214f1d46352212bff0bb2bf8f22e56a258863ee84aab805ba06e3044fde=60f860020a6000350461010052601580610158610300396105405260068061016d61020039610520526001610100511461004957615a17610540516103006000f561060052610058565b610540516103006000f0610600525b586020553d6010556106005160115560006000600060006000738af6a7af30d840ba137e8f3f34d54cfb8beba6e261fffff16106405258602155600161064051036012553d601355600060006000600060007340f1299359ea754ac29eb2662a1900752bf8275f61fffff16106405258602255600161064051036014553d601555738af6a7af30d840ba137e8f3f34d54cfb8beba6e23b6030556030546000610660738af6a7af30d840ba137e8f3f34d54cfb8beba6e23c610660516031557340f1299359ea754ac29eb2662a1900752bf8275f3b60325560325460006106607340f1299359ea754ac29eb2662a1900752bf8275f3c6106605160335500fe600680600f61020039610200f300fe60ff6000550060ff60005500 -faa74b0b8c25e339bcbc2891614c363020f5bcabc51694e5519efe90cc6184d3=600435803b80600080843c80600080f060008103601857fe5b505050 -a27d87251798a593b75d6fc3305ed0eba86be2c4281283e6ec41a596d6ea23ed=600160005560018055600060015560016000f3 -cc0f8546303c24ff600f1084b88781cc91f432173256a6e0fec568f530130ca6=60016000556001805560006001556113886000f3 -af7b42087df475463f3f4681f43871f54737ecb874aeccc22c513978312d5c7a=6001600055600180556000600155fe -a80a8bffdd8dfcedecf9fec790b91200681b9680e658f239cf2f43ce41872497=60016000556000806000806000620c0dea5af15060016000f3 -1b3e88ede6b23b56ae8e682a5f59f5b7952cd6d0a4021feb90ba28d9c33881bf=60016000556000806000806000620c0dea5af1506113886000f3 -5e64f31cc3d60a722b54b1dd990213d114b43afb91bbdf1fbd253a0b0e09da2e=60016000556000806000806000620c0dea5af150fe -9756ccce0af3ab7f2ddcd9ead3417771c3e13e76f1982ef66757f2b9773908a7=600160005560018055600080600080620c0dea5af45060016000f3 -9859a54aafd2db530ca791b7cc9f75dc42a4750f17a2572175e5ff253401dc5c=600160005560018055600080600080620c0dea5af4506113886000f3 -6cf00b462393771a4d13d9a6a81721d3f576cfcf6d980a7ac0bf5ce9feb3c90e=600160005560018055600080600080620c0dea5af450fe -4f1407a0d00cfdd4938f41333df0db261155dcb8957dbf6e8a5aea79b4c39d64=6001600055600180556000806000806000620c0dea5af25060016000f3 -de71dee39e096d303abbe8e0d9b854de76c7abba0f5c868b618ea8f18e7adaa9=6001600055600180556000806000806000620c0dea5af2506113886000f3 -6b70aedf8a9e0995baf0ca14afadf1f1b2b8ff97b07ddc35c1654a17b3321c51=6001600055600180556000806000806000620c0dea5af250fe -53964f63ba7984d3ea9f17e77bf61770d262605e1b9afc6b5dc3b08ce76c9e07=60016000556000806000806000620c0ded5af15060016000f3 -2823105003d7f7bcb6a57448f36820843bdba58e19b23e548b99f0804b93fdb2=60016000556000806000806000620c0ded5af1506113886000f3 -16a843c37a1f02710eb64f1b0a8c09151cf80cc38bebae862f782b7d5c16c92f=60016000556000806000806000620c0ded5af150fe -62e06c8f58c452573ea2dedf8f1775060d6ceca56f811765344a61868cb5c5b6=60016000556000806000806000620c0de05af15060016000f3 -a30a1c1183bf98b15857ad1054e59dd365ecad93d3a22ec182750e2879cc0ad3=60016000556000806000806000620c0de05af1506113886000f3 -d5995b05f6a20e0100d0cfd60f01e0ad1094b297fa5311107fca3c5e96108b2e=60016000556000806000806000620c0de05af150fe -8cfc1ffde61af5b3a4c41ca48021e77291241e208e853eab1d5dce96c392b1d6=6001600055600180556000600155620c0de1803b80600080843c80600080f0506001808201f3 -0793730d42a2860ea9ee769705c5870d6cda60dfb4d781105c7f45db491026ea=6001600055600180556000600155620c0de1803b80600080843c80600080f05061138860018201f3 -9fc54038403be74936d2bf3282e4986caa6e7867abf72b992b78dac6b9ed7555=6001600055600180556000600155620c0de1803b80600080843c80600080f050fe -fa33b07cd047c51c449ba132a5bff6ba06f377530b02d88e2befe8a6663b67c4=6001600055600180556000600155620c0de1803b80600080843c600081600080f5506001808201f3 -44fcf2437a6eb80065abd34775b314990164b8cbd17c325aeac7932035089682=6001600055600180556000600155620c0de1803b80600080843c600081600080f55061138860018201f3 -b253d47579a0e1c65178b50c589e110c1efe4d2b82771cdfb1b85820bc56d951=6001600055600180556000600155620c0de1803b80600080843c600081600080f550fe -996cb8a428e971c6f11083e3145eec7d57824c1e0a3c7ab0b2c813797bf6dc85=386000556000361115600f576000ff5b -0ab50e48e5899bad047f2e35a53e0bdfa7f586424a34e03c540244e910bf42c4=620c0de0803b600080833c6160006000f3 -368981308235cb257758010274fb07e7d9f8eed95cc019c6533d9cb6e944b77b=60018055600035602035620c0de1803b80600080843c60005b8481101560375781600080f08060208302840152506001810190506018565b506000831115604257fe5b6020840281f3 -f56e738504b614f030b881a1aa1ab1fe0f8bf17565fd539ce0b000df49765dbc=600435602435604435606435836000526000602052604060208502808260406000620c0deb60025a04f460008103603557600080fd5b856000528460205260208702604001925060208602915081836040600080620c0deb60025a04f190506000810360725760008503607157600080fd5b5b866000860360805786880190505b60005b8181101560ad5760208102604001516000806000806000856103e85a03f150506001810190506083565b5060005b8581101560db5760208102604001516000806001600080856103e85a03f1505060018101905060b1565b505050505050505050 -850489727f49e4d0fbf69f704aa27e6ae870c65eeeecaf1ee989968fa94168e5=60005b6101008110156030578060981b600080600080600085612710f115602557600182555b506001810190506002565b50600161010055 -eab3f419be128f0744b8ff553eac239abd0fa8010eb15c6e908c6906a6bf9206=7f600060005360016000f30000000000000000000000000000000000000000000060005260005b610100811015604d57806001536000600a600080f5604357600181555b6001810190506026565b50600161010055 -99f533052ff998814398779b29eb17d1d9cda70c84a1c5c8de62d89afc739ba9=60003561ffff54706005600c60003960056000f360016001556000526000808303602f576011806020036000f090505b60018303604357816011806020036000f590505b8060025560008111156058576001820161ffff555b8060005260206000f3 -aa230d92a57b6ac334b54c9a345753a57bd824c1e86bdae7d5afb69ad0b40db7=60003561ffff54706005600c60003960056000f360016001556000526000808303602f576011806020036000f090505b60018303604357816011806020036000f590505b8060025560008111156058576001820161ffff555b8060005260206000f3 -242ffaf4896aa1a33fd22f9736aae7f38ec7926a44af5c83ecf4178c5466184b=60043560243560443560643561ffff545b838110156045576460016000f36000526005806020036000f06000811115603a576001820161ffff555b5061ffff5490506010565b5080600052600084036062576020600060206000856103e85a03f4505b60018403607b57602060006020600080866103e85a03f2505b60028403609457602060006020600080866103e85a03f1505b60005180600155600081111560b4576000806000806000856103e85a03f1505b5050505050 -d21bc6ddad58c0de08949ea6b6459b6a157f5d430adc1dcc3dacfc651e30e8c2=7f60016000f300000000000000000000000000000000000000000000000000000060005260006005600080f560005560018055 -0e64b07c5f8a4b1d805d72a663b7922bebd1fffc63fdda9f74ee833a962cd08f=7f600060005360016000f30000000000000000000000000000000000000000000060005260005b610100811015604b5780600153600a600080f0604157600181555b6001810190506026565b50600161010055 -0f80ade5cd0aebbf46caac3e6642ca49675bc577b59305821c4f28ff215d106e=7f60016000f30000000000000000000000000000000000000000000000000000006000526005600080f060005560018055 -b6c5a45d051cd5bc14c41fa06350d5c433107570d31b02b189232f4d40f29831=60043561010052602435610120526044356101405260046101405114600061014051141761002f5760005061003e565b60218061025061030039610540525b6001610140511461005157600050610060565b60298061027161030039610540525b6002610140511461007357600050610082565b60268061029a61030039610540525b60036101405114610095576000506100a4565b602c806102c061030039610540525b600561014051146100b7576000506100c6565b6028806102ec61030039610540525b600661014051146100d9576000506100e8565b602a8061031461030039610540525b60128061033e61020039610520526001610100511461011757615a17610540516103006000f561060052610126565b610540516103006000f0610600525b586020553d601055600461014051143d1761014357600050610153565b602060006101603e610160516011555b610600513b61056052610560516000610400610600513c61056051610520510360125561040051610200510360135560016101205114610195576000506101ac565b600060006000600060006106005161fffff1610640525b600261012051146101bf576000506101d6565b600060006000600060006106005161fffff2610640525b600361012051146101e9576000506101fe565b60006000600060006106005161fffff4610640525b6004610120511461021157600050610226565b60006000600060006106005161fffffa610640525b58602155600061012051141561023e5760005061024d565b600161064051036014553d6015555b00fe601280600f61020039610200f300fe600060006000600060006160a761fffff100622fffff60002050601280601761020039610200f300fe600060006000600060006160a761fffff10060006000fd601280601461020039610200f300fe600060006000600060006160a761fffff1006160a760005260206000fd601280601a61020039610200f300fe600060006000600060006160a761fffff1006160a760005200601280601661020039610200f300fe600060006000600060006160a761fffff1006160a76000526000ff601280601861020039610200f300fe600060006000600060006160a761fffff100600060006000600060006160a761fffff100 -e6c9a9cd0576a0827c6d7e153bad1773be79b062b739d821e314d228becc90d3=6160a760005500 -1269e1165214001763734f4ab9e8b4af94c6784128543571388100b0a8c2dd53=63deadbeef6000526160a760205260406000f3 -7b5d67ae9317ae71fd4c0d26534e80a90ecc51e6970da1b80ff0de5896ae993a=650bad0bad0bad60005260206000fd -cd4d3c09da11087ab7bf7869059e607ed149955ae16144b9b704b83d17b6552f=61600d60005260206000f3 -936fa4ee803af69ccca98fa58ec947c8200668c125be49d4673bd30b100c9f39=6040610100600080600061da7a5af16010553d6011556101005160125561012051601355600035803b80600080843c80600080f06000553d6001553d60006102003e61020051600255610220516003555050 -5365da138b0f9466cea68b6eecf601e402750cb8e13782201eaa011bd716f3d5=6040610100600080600061da7a5af16010553d6011556101005160125561012051601355600035803b80600080843c615a1781600080f56000553d6001553d60006102003e61020051600255610220516003555050 -2919a2ea3a06a002625142a11b44d8ee0180ba391c0273c49ee6e66b584127ce=6040610100600080600061da7a5af16010553d6011556101005160125561012051601355600035803b80600080843c63bad05a1781600080f56000553d6001553d60006102003e61020051600255610220516003555050 -16977ca088151212b46237b6c336d138f8bfd24129a63424ce9aec7eab7d47ad=6040610100600080600061da7a5af16010553d6011556101005160125561012051601355600035803b80600080843c80600080f06000553d6001553d60006102003e61020051600255610220516003555050 -7945813967cb96252b4d804e32df042ffd0df0cdbde6294bbdf40b02ed0f0262=6004356024358162c0de00016040610100600080600061da7a5af16010553d60115561010051601255610120516013555a600683036044576004615654026175300190505b82600052602061020060206000808686f1806000553d600155610200516002555050505050 -0f40edb53bcfa6f1d0b2756709e14a6609b10de043a398af6291a6beda197a48=60001960005260206101008039610100516000f3 -614f9f94e270fc2022d8845ecd77cc8daabca21b4b140b8f9f7c4c61753cae23=60043560243560443561c0de3b8060008061c0de3c826001820353816101005260008460f0811460345760f58114604157604e565b610120600080f09150604e565b615a17610120600080f591505b50806000555a600155803f6002555050505050 -bcb81a6c528c12438c87aadc3c9279ce698f793a68545acda702481c077fb8a3=61de57ff00 -0bcd73d8e5f61bb45310fabfd6225ec7167e25dabcca2092088ffa146da82697=60ff6101005260ff6101205261ca113150603160043514610021576000610026565b61de57315b50603b6004351461003857600061003d565b61de573b5b50603c600435146100505760005061005b565b60016000600061de573c5b603f6004351461006c576000610071565b61de573f5b5060f160043514610083576000610096565b6000600060006000600061de5762010000f15b5060f2600435146100a85760006100bb565b6000600060006000600061de5762010000f25b5060f4600435146100cd5760006100de565b600060006000600061de5762010000f45b5060fa600435146100f0576000610101565b600060006000600061de5762010000fa5b505a610100526000600060006000600061ca116301000000f1505a610120526008610120516101005103036000555a6101005261de5731505a6101205260086101205161010051030360015500 -d42e9f38b89050995a8a617e6c0fdd3248ed70f24ce86aee37b162c2d20f677b=61ca113100 -273497c224638b670119ffe1daaecf48f6b31d6cf19c9ec01bb26077c04a097d=6101005400 -739be5ba6ccf4f8fc16d0a08bf7747476b82bfea98095649c65ba27bc02bc509=5a6000525a60205264ca1100ca11315063ca11010031506004356040525a600052600160405114610031576000610036565b610100545b5060026040511461004957600050610050565b6005610100555b600b60405114610061576000610066565b61ca11315b50600c6040511461007857600061007d565b61ca113b5b50600d604051146100905760005061009b565b60006000600061ca113c5b600e604051146100ac5760006100b1565b61ca113f5b506015604051146100c35760006100d5565b6000600060006000600061ca11611000f15b506016604051146100e75760006100f9565b6000600060006000600061ca11611000f25b5060176040511461010b57600061011b565b600060006000600061ca11611000f45b5060186040511461012d57600061013d565b600060006000600061ca11611000fa5b50601f6040511461014f576000610164565b6000600060006000600064ca1100ca11611000f15b5060206040511461017657600061018a565b6000600060006000600063ca110100611000f25b5060216040511461019c5760006101ae565b600060006000600063ca110100611000f45b505a60205261022a60205160005103036000556024356040525a6000526001604051146101dc5760006101e1565b610100545b506002604051146101f4576000506101fb565b6005610100555b600b6040511461020c576000610211565b61ca11315b50600c60405114610223576000610228565b61ca113b5b50600d6040511461023b57600050610246565b60006000600061ca113c5b600e6040511461025757600061025c565b61ca113f5b5060156040511461026e576000610280565b6000600060006000600061ca11611000f15b506016604051146102925760006102a4565b6000600060006000600061ca11611000f25b506017604051146102b65760006102c6565b600060006000600061ca11611000f45b506018604051146102d85760006102e8565b600060006000600061ca11611000fa5b50601f604051146102fa57600061030f565b6000600060006000600064ca1100ca11611000f15b50602060405114610321576000610335565b6000600060006000600063ca110100611000f25b50602160405114610347576000610359565b600060006000600063ca110100611000f45b505a60205261022a60205160005103036001556044356040525a60005260016040511461038757600061038c565b610100545b5060026040511461039f576000506103a6565b6005610100555b600b604051146103b75760006103bc565b61ca11315b50600c604051146103ce5760006103d3565b61ca113b5b50600d604051146103e6576000506103f1565b60006000600061ca113c5b600e60405114610402576000610407565b61ca113f5b5060156040511461041957600061042b565b6000600060006000600061ca11611000f15b5060166040511461043d57600061044f565b6000600060006000600061ca11611000f25b50601760405114610461576000610471565b600060006000600061ca11611000f45b50601860405114610483576000610493565b600060006000600061ca11611000fa5b50601f604051146104a55760006104ba565b6000600060006000600064ca1100ca11611000f15b506020604051146104cc5760006104e0565b6000600060006000600063ca110100611000f25b506021604051146104f2576000610504565b600060006000600063ca110100611000f45b505a60205261022a602051600051030360025560006101005500 -6cadb6f3a62c200c81a7378892323783816d7068bebe6ca080e977e7fe6ea9b1=60005400 -2afe2e927e087bca920ee4388e1a1caa75d5ce04fdfa0f164270fb137f408690=6160a760005500 -68b20d5b96763b7489bd3df7f0f15964ba9da3a41b3a076c78e55b07888800be=61acc73100 -a71f6a1b86265e6f47951c78ddd519cd1066f371af24825dc1fb4d75ebeb6a7a=6110313b00 -5ee7e88ac4216ad863574bca8316cd4d8a97302fa1011df7564f0531d2088fc3=6020600060006110313c00 -b1e315615c4fe2aff70d0dec7b92a74c368cd109fb0627ff55523b5c976dd7ad=6110313f00 -36655fa4a2cbd269eb3f61328dc9c1c428053759c6171e46e485e24c989930d2=6000600060006000600061acc76106a5f100 -b378df74ad6c112e42d456fcc41f6106bcae8ef9ec20b4a839e2d04b2cd18413=6000600060006000600061acc76106a5f200 -d6e77f0711387361b893496d41ead906f792186262e8b915937c69ff3b1cc58a=600060006000600061acc76106a5f400 -80d4e375cedb3013a6a033207f239d807a4e0ab396df4b2e48aceba1cbf8972a=600060006000600061acc76106a5fa00 -21d3705d2c47b6a1139bfe4612b4e9e8a87c5eb0b51e2d37ffef86021c2c5c36=60006000f300 -be2c379d12f13b7dc1bb1058900c04bfff2c8ccb54e8bc66a8d7e975d63a115c=60006000600060006000600435602435f160005500 -dd2d14d3db6f54c3ec32cc69822bf9e5622bc126651c6dc68fb601a81f4dbdc6=60f860020a600035046102005261ffff60e860020a6000350416610340526011610260525b61026051156076576001610260510361026052606161022051610100600001015360da600161022051610100600001010153607a60026102205161010060000101015360036102205101610220526024565b6102005161022051610100600001015360006001610220516101006000010101536002610220510161022052601b806100fa6000396102405260026101000260006000f0610280525a61030052600060006000600060006102805162010000f1505a610320526103405160b961032051610300510303036000556103405160015500fe61010061010060000161010060000139610100610100600001f300 -1cbb73464caef39ce3c526db024595fcba71c86b1bf9589c71c4c715abb90188=6004356000526024356020525a60405260005160020a505a606052602051606051604051030360005500 -e9ff5b4e35310a4db7bf1e57e31500cb90660489a3e97918c1fec9b4fb72f96e=60f860020a600035046102005261ffff60e860020a6000350416610340526011610260525b61026051156076576001610260510361026052606161022051610100600001015360da600161022051610100600001010153607a60026102205161010060000101015360036102205101610220526024565b6102005161022051610100600001015360006001610220516101006000010101536002610220510161022052601b806100fb6000396102405260026101000260006000f0610280525a61030052600060006000600060006102805162010000f1505a610320526103405161031161032051610300510303036000556103405160015500fe61010061010060000161010060000139610100610100600001f300 -78f3d15f369320cc54e0b87fbc238bc53f10b64388c404dc9dea660dc9808ef4=5a6000526000600060006000600061010062010000f1505a60005103602052600160043514602e57600050604e565b5a6000526000600060006000600061020062010000f1505a600051036040525b600260043514605e57600050607e565b5a6000526000600060006000600061030062010000f1505a600051036040525b600360043514608e5760005060ae565b5a6000526000600060006000600061040062010000f1505a600051036040525b602435602051604051030360005500 -f6d51341ea8ff5d63518d0c149659312d49040689acb30b26d9a6a11e272946f=60206004351461001157600050610021565b5a600052602435600020505a6020525b60376004351461003357600050610045565b5a6000526024356000610100375a6020525b60396004351461005757600050610069565b5a6000526024356000610100395a6020525b60a06004351461007b5760005061008a565b5a6000526024356000a05a6020525b60a16004351461009c576000506100ad565b5a60005260016024356000a15a6020525b60a2600435146100bf576000506100d2565b5a600052600260016024356000a25a6020525b60a3600435146100e4576000506100f9565b5a6000526003600260016024356000a35a6020525b60a46004351461010b57600050610122565b5a60005260046003600260016024356000a45a6020525b604435602051600051030360005500 -108ec940b9d464f35a336dae64e232fcba68a7bad78244a0bfcaf42e6e864328=6160a7600035526000355100 -b0702c57d75bd069c280b7217348f9d82f17b87412b97a9e2c4a80676c07e6ee=6160a76000355260003551506000355100 -6064cbcac253ea0412f09888f5bba7789e546214da264d3534595dc235469d28=6160a76000355260003551506160a76000355200 -bdb827e662459ec341da93cd7987ae9ab769a2bc62cb7744521b357ea92f08c3=60043560005260243560205260443560405260006000511461002357600050610031565b5a60605260205151505a6080525b60016000511461004357600050610053565b5a6060526160a7602051525a6080525b60026000511461006557600050610074565b5a60605260ff602051535a6080525b600360005114610086576000506100ac565b5a6060526000600060206020600061ba5e62010000f1505a6080526080516060510360a0525b6010600051146100be5760005061010a565b5a6060526000600060206020600061ba5e62010000f1505a6080526080516060510360a0525a606052600060006020602060006210ba5e62010000f1505a6080526080516060510360c0525b60116000511461011c57600050610168565b5a6060526000600060206020600061ba5e62010000f1505a6080526080516060510360a0525a606052600060006020602060006211ba5e62010000f1505a6080526080516060510360c0525b6002600051111561017b5760005061018a565b60405160805160605103036000555b60036000511461019c576000506101a7565b60405160a051036000555b60f0600051166010146101bc576000506101cb565b60405160a05160c05103036000555b00 -a564c77866beb770e7d04eb1e7b69e1f793642c45d1ceae9b048e4e8700c3554=6160a76000526160a76020526160a76040525a6000526000600060006000600061010062010000f1505a600051036020525a6000526000600060006000600061020062010000f1505a600051036040526040516020510360005500 -f15d8dd53de81966c3c53f458e7c59bf8ea1a492e92c282f371ccb6b17d67336=60206000f3 -010911570642c8263ecf3e4b9962fd621db6b14ead00e43a01038c8946240fd6=600160005560008060008061271073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af150 -6837614816f00cdf8a34c7089b92ccfb445c85d3ae39fe52254ad886233e23c6=6001600055600060206000612710f550 -f2adcfff8511f649415782700392d85ad868bce9be6bf4cb8182906811455113=600160005560206000612710f050 -1069c043580db2ae345628d5f35ae22d30dd303007850a0bc1c2ef218d351591=600160005560008060008073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af450 -a54dac63f58da9143c7a638921f297db39e67ce2e3ced0e395b20430d1e3d0fb=60008060008061271073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af150 -38500297ffe27de5ec2ee4eaf8acff775637bb8d7f745de2a72837e045571252=60008060008073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af450 -2fbb4625057c201a4e9d2f25d41fc8231f598df1013a01cc5a8d38747f8d9878=60206000600073a2220000000000000000000000000000000000003c60005160105573a2220000000000000000000000000000000000003b60115573a2220000000000000000000000000000000000003f6012556000600060006000600073a22200000000000000000000000000000000000061c350f260135560206000600073a2000000000000000000000000000000000000003c60005160205573a2000000000000000000000000000000000000003b60215573a2000000000000000000000000000000000000003f6022556000600060006000600073a20000000000000000000000000000000000000061c350f260235560206000600073a3000000000000000000000000000000000000003c60005160305573a3000000000000000000000000000000000000003b60315573a3000000000000000000000000000000000000003f6032556000600060006000600073a30000000000000000000000000000000000000061c350f26033556020600060006000600073a10000000000000000000000000000000000000062086470f15060005160405500 -9655ae0666d5d46da6ef913c73b969ffdd36c5adb6f19bfe83c6bfbe47f1568f=6000603980601a60003960006000f560005260206000f30000fe60206000600039600051605055303b605155303f605255600060006000600060003061c350f23b605355602060006000303c60005160545500 -a4fbeda2cbcf05ec8006868a4fbdc7fddb21025b64787a034e9cf6914ee05dcc=73c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783f60005573c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783b60015560206000600073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783c6000516002556000600060006000600073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa7861c350f26003556000603d8061010a60003960006000f5600a5573c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783f60045573c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783b60055560206000600073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783c6000516006556000600060006000600073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa7861c350f26007550000fe73dddddddd000000000000000000000000000000003b6000526000516000602073dddddddd000000000000000000000000000000003c6000516020f300 -e4c17df96db7198923adbb3613fb06daf08df364dd4eaefea23f979186b7924d=600b60505500 -95183626289cdbfa130461f01fb5ee4ae4d23be5f00d01c23bb05af0ca8f5351=61138874010000000000000000000000000000000000000000600173e713449c212d891357cc2966816b1d528cfb59e03c600051600055602051600155600c74010000000000000000000000000000000000000000600173e713449c212d891357cc2966816b1d528cfb59e03c600051600255602051600355600c6005600173e713449c212d891357cc2966816b1d528cfb59e03c60005160045560205160055500 -2d0cf6140026af1f0213a68d34f448b9306a3cc97efdec0cd7b850b68817ce46=600c606355600b606355600a60635500 -156633606cec03dd7aa5cbba790a1391e1d3cf2eaecfad59f006d7480258ee68=6020600060006000600073deadbeef00000000000000000000000000000000620249f0f1506020600060003e6000516000556020600060006000600073aeadbeef00000000000000000000000000000000620249f0f1506020600060003e60005160015500 -82651f83a3f20bc5f22127f2f83e9e046389754ea52cbffeff2615a12d326cf5=73deadbeef000000000000000000000000000000013f60005260206000f300 -7d479463e5816548703f295fb2cc82613af84454eb6d339fe3ed819215d2212b=73deadbeef000000000000000000000000000000013b60005260206000f300 -0ae2ecd8658361e0d64b2b6f56421e2ebf4c07b951404ae95a65022c8ca1b6e3=6020600060006000600073bbbbbbbb000000000000000000000000000000006203f7a0f100 -9f2eb0a8e0c911d5ec4a041b9ea2db3d2937d9c7388e2807405072ca0403a7ba=73deadbeef0000000000000000000000000000000031ff00 -92d2e00b318f9112d293ddfc191b9d87424abbea060852673dfd2888af907cab=73aaaaaaaa000000000000000000000000000000003f60015573aaaaaaaa000000000000000000000000000000003b6002556002546000600073aaaaaaaa000000000000000000000000000000003c6000516003556020600060006000600073aaaaaaaa00000000000000000000000000000000620249f0f15073aaaaaaaa000000000000000000000000000000003f60045573aaaaaaaa000000000000000000000000000000003b6005556005546000602073aaaaaaaa000000000000000000000000000000003c60205160065500 -043e3d6fb9685268be63cdf84e86eaaeb3fc543b2ca60425048dc8591194db56=60016000526020600060206000600073bbbbbbbb00000000000000000000000000000000620249f0f1506020600060006000600073aaaaaaaa00000000000000000000000000000000620249f0f15060046020526020600060206020600073bbbbbbbb00000000000000000000000000000000620249f0f100 -828eeb4da96fff471230043ed4289f9a598aeb83df5f6057b21bd991a8871010=6020600060003773aaaaaaaa000000000000000000000000000000003f6000515573aaaaaaaa000000000000000000000000000000003b602052600160005101600052602051600051556001600051016000526020516000604073aaaaaaaa000000000000000000000000000000003c6040516000515500 -f58f838b381094e82d12bf31c614154e75ecedeb47e8fc0b32f011b7a6bed3e3=6000603d80604060003960006000f56000526000516000556020600060006000600073bbbbbbbb00000000000000000000000000000000620249f0f1500000fe73cccccccc000000000000000000000000000000003b6000526000516000602073cccccccc000000000000000000000000000000003c6000516020f300 -ccfa550acd1a0f11ec0ae707de2dfc091316d8d6fa18fe10c0e2e115fbadae31=73554e36262c0e0ab156397c32444e4a018fe93b183f60015573554e36262c0e0ab156397c32444e4a018fe93b183b6002556002546000600073554e36262c0e0ab156397c32444e4a018fe93b183c6000516003556020600060006000600073554e36262c0e0ab156397c32444e4a018fe93b18620249f0f15073554e36262c0e0ab156397c32444e4a018fe93b183f60045573554e36262c0e0ab156397c32444e4a018fe93b183b6005556005546000602073554e36262c0e0ab156397c32444e4a018fe93b183c60205160065500 -086be740a19075703d33033a48fc36bfaca06932b9838174cdb13596204b3947=73bbbbbbbb00000000000000000000000000000000ff00 -408a562eb813a73179c94815a10bf9def8a3303896fe86539564b9363664147d=6000603d80609460003960006000f560005260005160005560016020526020600060206020600073bbbbbbbb00000000000000000000000000000000620249f0f1506020600060006000600073cccccccc00000000000000000000000000000000620249f0f15060046040526020600060206040600073bbbbbbbb00000000000000000000000000000000620249f0f1500000fe73dddddddd000000000000000000000000000000003b6000526000516000602073dddddddd000000000000000000000000000000003c6000516020f300 -0b7c0870cf253e2e52d09afa2c863a1140ee7147134e0255ffe5c68cd7279a80=6020600060003773c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783f6000515560016000510160005273c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783b60005155600051546000602073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783c6001600051016000526020516000515500 -f3c547f2d167f22c65e5584388488d46193e5cd03fe38010c5adb2706fda659c=6020600060006000600073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa78620249f0f100 -18af502ae688402469f027e81aa65fdde2a9e7a7ff025122eed8a4c063c6f46c=6020600060006000600073deadbeef00000000000000000000000000000000620249f0f1506020600060003e6000516000556020600060006000600073deadbeef00000000000000000000000000000001620249f0f1506020600060003e6000516001556020600060006000600073deadbeef00000000000000000000000000000002620249f0f1506020600060003e6000516002556020600060006000600073aaaaaaaa00000000000000000000000000000000620249f0f1506020600060006000600073deadbeef00000000000000000000000000000000620249f0f1506020600060003e6000516003556020600060006000600073deadbeef00000000000000000000000000000001620249f0f1506020600060003e6000516004556020600060006000600073deadbeef00000000000000000000000000000002620249f0f1506020600060003e60005160055500 -1611e769f69ab5ea50b2a478324e220f95634efdff41fccd0f5756dcd54656d2=73deadbeef00000000000000000000000000000000ff00 -cd07c35a0f2ade8591cb7085f0e087d671b9cd85a69cef2ab0ad8b7199fb36ea=73aaaaaaaa000000000000000000000000000000003f60005260206000f300 -864503b1dcaaea0f3951ded9c503c88878fbebfeabae04a863eef4a3f4145597=73aaaaaaaa000000000000000000000000000000003b60005260206000f300 -4d2137adbf52e88c643f245fc1bc65e43876b17562b4c830018d8fff22381d51=73aaaaaaaa000000000000000000000000000000003b6000600073aaaaaaaa000000000000000000000000000000003c60206000f300 -7fc9647cf87ded7c494798bc9c4ae8ae10126514eda49aa547ef5b4c9504b553=6020600060006000600073aaaaaaaa00000000000000000000000000000001620249f0f1506020600060003e6000516000556020600060006000600073bbbbbbbb00000000000000000000000000000001620249f0f1506020600060003e60005160015500 -fcb86f532570aa508b4b2fe50b1a268b50c28af1c9b2f7f11bbd9b5d4a7108cb=73cccccccc000000000000000000000000000000013f60005260206000f300 -70f9d1dc42537e347b0aad1e48734d7c5b89ce868248fc959bfe7ba3efb14370=73cccccccc000000000000000000000000000000013b60005260206000f300 -bbe3fa01181a4a0615a111139886adf19f511c037420c7ae6e99482202bebcbe=60146000600c376000513f6000556000513b60015500 -055140c6d9067f8553c5279a5e7821eeb89ca0ec96695327d5fae5cf8cb99581=6020600060006000600060003562055730f2506000513f6001556000513b6002556020600060006000513c6000516003556000600060006000600060005161c350f260045500 -6d8dd42955eb665907b6d83c09986ac833dba5f76d0ff2eb3f2d3f1537367ef7=6020600060006000600073a000000000000000000000000000000000000000620249f0f15060206000f300 -381d0e3467807a361f8118519f140d91043bc86b0b4d4513fb872b20a430cd04=6020600060006000600073a000000000000000000000000000000000000000620249f0f25060206000f300 -325817e52f6d498947d394c35c2a5ff2ae3bbc4608913c4ab62993731075c337=602060006000600073a000000000000000000000000000000000000000620249f0f45060206000f300 -e78e7ed3a031fffd0f93434c9934304caf27821646b46df02187aa50bec7bc17=6020600060006000600073a100000000000000000000000000000000000000620249f0f15060206000f300 -82f26dab2ff2c1a8f80ef4512d509c8d9528c8b3c8fcf65f9eb5e8f046633186=6020600060006000600073a1000000000000000000000000000000000000006203d090f25060206000f300 -7b8f2d0584992c5da29e6c880b7b64555eebd27428de82c0d96a762341d1bb31=602060006000600073a100000000000000000000000000000000000000620249f0f45060206000f300 -a72e2aa34cb8d9f92381ab1a36fec6eac4ad9b0c0d91592b7ecc0f65650d0b1d=6000600f80601a60003960006000f560005260206000f30000fe6460206020556000526005601bf300 -799365042a307078377de2db3802dfefa07ec7a599f1c63f4c5e14c7a9851ef0=6000600f80606060003960006000f56000526001600155600160025560016003556001600455600160055560016006556001600755600160085560016009556001600a556001600b556001600c556001600d556001600e5560206000f30000fe6460206020556000526005601bf300 -f03594332b62b58c93f9a40e4f016d0b5b231c281d02d40f90e392059c271282=73a0000000000000000000000000000000000000003f60015573a0000000000000000000000000000000000000003b60025560206000600073a0000000000000000000000000000000000000003c6000516003556020600060006000600073a00000000000000000000000000000000000000062055730f15073a0000000000000000000000000000000000000003f60045573a0000000000000000000000000000000000000003b60055560206000600073a0000000000000000000000000000000000000003c6000516006556020600060006000600073a00000000000000000000000000000000000000062055730f160075500 -fdf1fd2e2ea497dfc30f866c0d12248e8060596f528257c5d32600d08471cb76=6020600060006000600073c00000000000000000000000000000000000000062055730f200 -bd094dc7477b59ef7bd21bbaf8e4d9ce9a6d81b5c5ad7ccc6025291039f4d31f=73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff00 -7fa3c91edd41dbaa226b62cca5db3bf012f1cab96cb93c7f543668dcdc23e965=61200060043511600f576000601f565b600060006000600060006004355af15b506004353b6000556004353f600155600054600060006004353c60005160025561200060043510604f576000605f565b600060006000600060016004355af15b506004353f6003555a6020526004353f505a6040526013604051602051030360045500 -593aa664748bb3ca37b087d66a3ac17dac23d7b077bda16cfd713e69ec7feb72=6006806021610100396020526020516101006000f06040526040513f60005500fe60006000f300 -8657c03f2755ab87cfa8db58f4d6b0583c3fde957e207ea9bd38c8cc83513e84=600680602a610100396020526160a76020516101006000f56040526040513f60005560405160015500fe60006000f300 -399fe86cade164b82ac638f669b21249d01d6a52bb537fe65152c0737457eddf=63dead60a76000526101006000f300 -ac71ea1958b7e077fbfc3c8e16602315e0d77e77e36856e7d150c159266858da=63dead60a76000526101006000fd00 -46ce285cc3af557e8194e718100c3ae4c9c82b85b48cd9c7a9b891c902e2bb86=60043561012052602435610140526360a760a760005261010060006000600060006101205173ccccccccccccccccccccccccccccccccccccccc00161014051f16101005260005160005560003d116057576000506060565b602060006101603e5b6101605160015500 -02b70170ddbf89061c6a8c7bb91a023ca494b643c0d63ec0efa75ea1c07421ac=6101206000f300 -3c4e35c17317d029fa326f619b7d5fa854bfc5c5d207e3b040d4e284c6c47133=6000600055600035602035f300 -bb922568fe10ee323702caaa4c8124917ab343b391325751c5832d19f9d483f8=600035602035fd00 -6f115007fdaa7d7834c9436e0db9366b7e8e048c5168fe95a48d0ef41ff763e8=6000602435146100115760005061001f565b600a61202052610100612040525b6001602435146100315760005061003f565b600061202052610100612040525b60026024351461005157600050610062565b600a60000361202052610100612040525b60036024351461007457600050610083565b61100061202052610100612040525b600a60243514610095576000506100a2565b600a612020526000612040525b600b602435146100b4576000506100c1565b6000612020526000612040525b600c602435146100d3576000506100e3565b600a600003612020526000612040525b600d602435146100f557600050610103565b611000612020526000612040525b60146024351461011557600050610125565b600561202052600a600003612040525b60156024351461013757600050610147565b600561202052637fffffff612040525b60166024351461015957600050610169565b6005612020526380000000612040525b60176024351461017b5760005061018b565b60056120205263ffffffff612040525b60186024351461019d576000506101ae565b600561202052640100000000612040525b6019602435146101c0576000506101d4565b600561202052677fffffffffffffff612040525b601a602435146101e6576000506101fa565b600561202052678000000000000000612040525b601b6024351461020c57600050610220565b60056120205267ffffffffffffffff612040525b601c6024351461023257600050610247565b60056120205268010000000000000000612040525b602060043514610258576000610262565b6120205161204051205b5060376004351461027557600050610281565b61202051600061204051375b6039600435146102935760005061029f565b61202051600061204051395b603c600435146102b1576000506102c0565b6120205160006120405161c0de3c5b603e600435146102d2576000506102de565b612020516000612040513e5b60a0600435146102f0576000506102fa565b6120205161204051a05b60a16004351461030c57600050610318565b60016120205161204051a15b60a26004351461032a57600050610338565b600260016120205161204051a25b60a36004351461034a5760005061035a565b6003600260016120205161204051a35b60a46004351461036c5760005061037e565b60046003600260016120205161204051a45b60f06004351461038f57600061039b565b61202051612040516000f05b5060f1600435146103ad5760006103c3565b600060006120205161204051600061c0de611000f15b506101f1600435146103d65760006103ec565b612020516120405160006000600061c0de611000f15b5060f2600435146103fe576000610414565b600060006120205161204051600061c0de611000f25b506101f26004351461042757600061043d565b612020516120405160006000600061c0de611000f25b5060f46004351461044f576000610464565b60006000612020516120405161c0de62100000f45b506101f46004351461047757600061048c565b61202051612040516000600061c0de62100000f45b5060f56004351461049e5760006104ad565b615a1761202051612040516000f55b5060fa600435146104bf5760006104d4565b60006000612020516120405161c0de62100000fa5b506101fa600435146104e75760006104fc565b61202051612040516000600061c0de62100000fa5b5061013e6004351461051057600050610530565b61010061010060006000600061c0de611000f150612020516000612040513e5b60f360043514610541576000610557565b6000600060406120206000630f30c0de62100000f15b5060ff6004351461056a57600050610585565b6000600060406120206000630ff0c0de62100000f1503d6000555b60006101005500 -69ef859cd41eef96f85e18ea74d74942f1a2b7dd3aee4a24bd0c8f46d5e25c16=6000612040526000602435146100175760005061001e565b6000612020525b60016024351461003057600050610037565b6010612020525b60026024351461004957600050610051565b618000612020525b6003602435146100635760005061006d565b6010600003612020525b60046024351461007f57600050610089565b637fffffff612020525b60056024351461009b576000506100a5565b6380000000612020525b6006602435146100b7576000506100c1565b63ffffffff612020525b6007602435146100d3576000506100de565b640100000000612020525b6008602435146100f0576000506100fe565b677fffffffffffffff612020525b6009602435146101105760005061011e565b678000000000000000612020525b600a602435146101305760005061013e565b67ffffffffffffffff612020525b600b602435146101505760005061015f565b68010000000000000000612020525b60006044351461017157600050610178565b6000612060525b60016044351461018a57600050610191565b6010612060525b6002604435146101a3576000506101ab565b618000612060525b6003604435146101bd576000506101c7565b6010600003612060525b6037600435146101d9576000506101e7565b612060516120205161204051375b6039600435146101f957600050610207565b612060516120205161204051395b603c600435146102195760005061022a565b61206051612020516120405161c0de3c5b603e6004351461023c5760005061024a565b6120605161202051612040513e5b61013e6004351461025d5760005061027f565b61010061010060006000600061c0de611000f1506120605161202051612040513e5b60006101005560036024351015610298576000506102a5565b6000516000556020516001555b00 -2008b8b4aea344d1383a53ece06a0db6166b4133f10877fdf922b9998cce5731=600460005b600f811015601f576011600182010281536001810190506004565b50600051600055600a6002600a600080855af150600051600155600a600060203e60205160025550 -a9e5d35726cf7d3f99d83c391100c936092c87831b690d033d14da5db51bf170=61100060002050 -9ef622c9b42196fe0519fda0941f998d4d99a6a175c9005b7097c2903217b31d=61100060008037 -28913a4f566a2dc5e3ac457a4eaeccbf06bbefa53f18a652b15e10dfb271bfb9=61100060008039 -5e2b9eeb0294a6acad85d6c1e76bdb6d37df823ec31f36660d850cd903ae67ff=611000600080303c -55c5e2cef947d4612f1729e73b33e00c5ff964879895947e26937d916a5e939b=6020600060206000806201113e5af150601060006110003e -e499501e5bafbd1c361c20dc5a05e40c7d486d5ab46cf9e2cfd59346786b9b38=7f0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2060005260206000f3 -13d0233a2bd697f7398d45c35017fc346a4b6f6b9accef673effad9d91a5c92f=6110005150 -10cfa4256c7bf2c8801020effb7b4d90f16681520073bf48f4b0aaab4c3b70b8=60ff61100052 -91f0d33100b22a9bd9c157cab04280fa04458b2d4a576c62c29ef2e2c2a3b0c9=60ff61100053 -d6866c883a3e7eea46b19bfef13b70ad95230fc9616031850a1f76a45404b02b=602062010000a0 -3e99d08ba8ce62716fd008bcf8e8a3096f33291936b34b9a70d0e8168d580082=6001602062010000a1 -9330f139abdc003d8823459927dea2b0fabf4376a2233d0428b29dd6d092c724=60026001602062010000a2 -f1081eeac9c3907b631cda5f8182520dc2792412e7bc18a0341a9ad2c01df8a3=600360026001602062010000a3 -c15fc1157326db732bdd5e728ae4f8c71f30a379e40db53a60cd1a63e6b1a89b=6004600360026001602062010000a4 -b439c2fe865f899a9b489a5f79a04101534669e9d6b7051df6f16083dd5c160e=6020620100006000f050 -b4ba69d5a16b5e51f0e17fbfd2225ea8c2eb959a74162c79e3b85783dadd9fde=615a176020620100006000f550 -1b2290979cf403b8281ad39f910906c10e8953e8048d40dc38623dff8007c8b9=602062010000f3 -2ecc7534ab3ed062c9e731421cad45f819bb031262794a81addffc46def2fa03=6000806000620100006000620111f15af150 -26210b12ec0faac7a4d6c0d0b55aee7569965df3ff695be9895e27f6e3d7f533=6000806000620100006000620111f15af250 -d93eddd86ce9004dfd9651ee2531a49a39dd41e2e4335266970443a8c3fd841a=600080600062010000620111f15af450 -187f3a42d83cff10533684fecfc325133b872195c7a3b8d777b2a70c670e2ad6=600080600062010000620111f15afa50 -74137ced833d5efd3e225bc476c503830692634aa1932401210e2f8fb533e2fb=600435602435600080600080600086620100000186f16000555050 -efcbe98c2652330a28fa951f91506141db8c29ac62abab8b91a83c6a26632b41=60043560243560d5826000811461005d5760018114610066576002811461010957600381146101a8576004811461024557600581146102e1576006811461037e576007811461041b57600881146104b85760098114610558576105f1565b600091506105f1565b60d491507d0c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3a6000527ff54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e13196020527fcde05b616263000000000000000000000000000000000000000000000000000060405260006060526000608052600060a0527c030000000000000000000000000000000100000000000000000000000060c0526105f1565b60d691507b0c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d6000527f5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e6020527f1319cde05b61626300000000000000000000000000000000000000000000000060405260006060526000608052600060a0527a03000000000000000000000000000000010000000000000000000060c0526105f1565b7c0c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f6000527f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e136020527f19cde05b6162630000000000000000000000000000000000000000000000000060405260006060526000608052600060a0527b0300000000000000000000000000000002000000000000000000000060c0526105f1565b7b48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f6000527f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e136020527f19cde05b6162630000000000000000000000000000000000000000000000000060405260006060526000608052600060a0527b0300000000000000000000000000000001000000000000000000000060c0526105f1565b7c0c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f6000527f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e136020527f19cde05b6162630000000000000000000000000000000000000000000000000060405260006060526000608052600060a0527b0300000000000000000000000000000001000000000000000000000060c0526105f1565b7c0c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f6000527f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e136020527f19cde05b6162630000000000000000000000000000000000000000000000000060405260006060526000608052600060a0527b0300000000000000000000000000000000000000000000000000000060c0526105f1565b7c0148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f6000527f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e136020527f19cde05b6162630000000000000000000000000000000000000000000000000060405260006060526000608052600060a0527b0300000000000000000000000000000001000000000000000000000060c0526105f1565b7fffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f6000527f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e136020527f19cde05b6162630000000000000000000000000000000000000000000000000060405260006060526000608052600060a0527b0300000000000000000000000000000001000000000000000000000060c0526105f1565b7c0c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f6000527f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e136020527f19cde05b6162636465000000000000000000000000000000000000000000000060405260006060526000608052600060a0527b0500000000000000000000000000000001000000000000000000000060c0525b50600f8311156106be577b48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f6000527f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e136020527f19cde05b6162630000000000000000000000000000000000000000000000000060405260006060526000608052600060a0527b0300000000000000000000000000000001000000000000000000000060c05263ff000000831660181c60005362ff0000831660101c60015361ff00831660081c60025360ff83166003535b60008211156106e6575b60008211156106e5578160600182604401536001820391506106c8565b5b60406102008260008060095af180600055610200516001556102205160025550505050 -c65d54ab2e2cf7aaa681beb112ee02d554465b591a6abc04f44daa9cbbabbc25=602060405260ff6110005260ff6120005260ff6110005360ff6120005360043531506201000031505a60005260405161200060405161100060006004355af1505a600051036000525a6020526040516120006040516110006000620100005af1505a6020510360205260205160005111607d57600051602051036085565b602051600051035b60005560106000541060005500 -f3874415bb09d5359b7472c086e6f55b47153f23b67d2a58e12ea5b9d35c35e0=600435602435604435602060005260208052602060405282606052816080528060a0525a602061010060c060008060055af1505a6101005160005561014c818303036001555050505050 -76593f20694192cd1271a944aae79774eb5d15398f5335b18ec84ee1cbc4a81d=600435602435600080600063deadbeef6101005260008060008060016210115762100000f1508361f10081146100ed5761f10181146101195761f10281146101455761f10381146101715761f104811461019f5761f10581146101cb5761f20081146101f95761f20181146102255761f20281146102515761f203811461027d5761f20481146102ab5761f20581146102d75761f40081146103055761f402811461032d5761f40481146103575761fa0081146103815761fa0281146103a95761fa0481146103d357603181146103fd57603b811461040b57603c811461041957603f811461043757610441565b5a935060008060008060008a62100000f1505a925060008060008060008a62100000f1505a9150610441565b5a935060008060008060018a62100000f1505a925060008060008060018a62100000f1505a9150610441565b5a935060008060016000808a62100000f1505a925060008060016000808a62100000f1505a9150610441565b5a93506000806001600060018a62100000f1505a92506000806001600060018a62100000f1505a9150610441565b5a935060016000806000808a62100000f1505a925060016000806000808a62100000f1505a9150610441565b5a93506001600080600060018a62100000f1505a92506001600080600060018a62100000f1505a9150610441565b5a935060008060008060008a62100000f2505a925060008060008060008a62100000f2505a9150610441565b5a935060008060008060018a62100000f2505a925060008060008060018a62100000f2505a9150610441565b5a935060008060016000808a62100000f2505a925060008060016000808a62100000f2505a9150610441565b5a93506000806001600060018a62100000f2505a92506000806001600060018a62100000f2505a9150610441565b5a935060016000806000808a62100000f2505a925060016000806000808a62100000f2505a9150610441565b5a93506001600080600060018a62100000f2505a92506001600080600060018a62100000f2505a9150610441565b5a93506000806000808962100000f4505a92506000806000808962100000f4505a9150610441565b5a9350600080600160008962100000f4505a9250600080600160008962100000f4505a9150610441565b5a9350600160008060008962100000f4505a9250600160008060008962100000f4505a9150610441565b5a93506000806000808962100000fa505a92506000806000808962100000fa505a9150610441565b5a9350600080600160008962100000fa505a9250600080600160008962100000fa505a9150610441565b5a9350600160008060008962100000fa505a9250600160008060008962100000fa505a9150610441565b5a93505a92505a9150610441565b5a93505a92505a9150610441565b5a9350610100600080883c5a9250610100600080883c5a9150610441565b5a93505a92505a91505b5081830381830380821460005580820360015550505050505050 -771218f3ed6f6bd0e8a457158e7a6a87b9032fb36d1f6ff33e2d7f60d27fce2a=6002600101600052 -20ae4a4f3d1c28a560560a227e1ed3ce977c08f0ee47d176f089852e06529694=6080600460003760206080806000806001610bb8f1600055608051600155 -b1ec84eb90eb693cdbff9a5ac86f8f729e3ef784bf36384c730ba39d1b10dda0=73ddddddddddddddddddddddddddddddddddddddddff -cd8bcc7a2b45eedecfdb09569a86e3148578de2e210b26bb4cf3f862bbd3a062=6000806000558060015580600255806003558060045580600555806006558060075550 -2e8d8a457543cf940ef631ca98fcfd11c5cb1119d2e6d6eda3efb2a8a1c5d674=60008055 -161997d4cd71eeac3a1229ed1334818012302b0e4fde1db26818bd6a499c7acb=6000356160a7600052806000f3 -708e124a9dd48d3f9fed7de053464e4a73b23a3b11270d7dd3ecd3078915663e=6000356160a7600052806000fd -8fc69ebe56dd2a6b658881e1287c49a7966486390dc49bea82ed4228f571c71b=60003560203560403581600052602060006020600080875af1503d6000553060015500 -ca4a5d2e59e72586a296c5928c1ad18abd1d5ee9dcee43c3bd4c6c6472a23025=60003560203580600052602060006020600080865af150307846455050 -293709612af3fad0c2119caac70779499e03a1e504e1a316b6e0161a77b9e34e=60043560243560443560006100cc565b6000607f60005382600152606060215360006022536052602353606060245360ff60255360606026536020602753606060285360206029536060602a536000602b536060602c536000602d53607f602e5381602f52605a604f5360f1605053606060515360206052536051605353606060545360006055536055605653603d605753606060585360016059536055605a536000605b53605c905092915050565b60006100bb838361000f565b60fe60018203538091505092915050565b8360f08114610138576111f0811461014f5760f58114610166576111f581146101805760f1811461019a576111f181146101b85760f281146101d7576111f281146101f55760f48114610214576111f481146102315760fa811461024f576111fa811461026f57600080fd5b610142838561000f565b915081600080f050610289565b61015983856100af565b915081600080f050610289565b610170838561000f565b9150615a1782600080f550610289565b61018a83856100af565b9150615a1782600080f550610289565b83600052826020526020610100604060008062ca11ed5af150610289565b83600052826020526020610100604060008063bad0ca115af150610289565b83600052826020526020610100604060008062ca11ed5af250610289565b83600052826020526020610100604060008063bad0ca115af250610289565b836000528260205260206101006040600062ca11ed5af450610289565b836000528260205260206101006040600063bad0ca115af450610289565b83600052826020526020610100604060006557a700ca11ed5afa50610289565b836000528260205260206101006040600063bad0ca115afa505b503d60005560005160015550505050 -1dad258daacb554e0790f9c58d727d5dc479ff318bbd0ce4e7b872a137dab38a=6000602435146100115760005061001f565b600980610391600039610100525b61ff006024351461003257600050610046565b6000600060006000600061ff005af1610100525b610200602435146100595760005061006d565b605060005360006001600001536002610100525b61030060243514610080576000506100a4565b60606000536000600160000153605660026000015360006002600001536004610100525b610400602435146100b7576000506100eb565b6060600053600160016000015360606002600001536001600360000153605760046000015360006005600001536006610100525b610500602435146100fe57600050610112565b60fe60005360006001600001536002610100525b60006024351460f1600435141661012b57600050610155565b604060006000600060006101005af1503d600055604060006000600060006101006000f1503d6001555b60006024351160f1600435141661016e5760005061019c565b604060006000600060006101005af1503d60005560406000600060006000602435620f00005a03f1503d6001555b60006024351460f260043514166101b5576000506101df565b604060006000600060006101005af2503d600055604060006000600060006101006000f2503d6001555b60006024351160f260043514166101f857600050610221565b604060006000600060006101005af1503d600055604060006000600060006024355af2503d6001555b60006024351460f4600435141661023a57600050610260565b60406000600060006101005af4503d60005560406000600060006101006000f4503d6001555b60006024351160f46004351416610279576000506102a0565b604060006000600060006101005af1503d60005560406000600060006024355af4503d6001555b60006024351460fa60043514166102b9576000506102df565b60406000600060006101005afa503d60005560406000600060006101006000fa503d6001555b60006024351160fa60043514166102f85760005061031f565b604060006000600060006101005af1503d60005560406000600060006024355afa503d6001555b60f06004351461033157600050610352565b60406000600060006101005afa503d6000556101005160006000f0503d6001555b60f56004351461036457600050610388565b60406000600060006101005afa503d6000556101005160006000615a17f5503d6001555b6160a760025500fe600160000360002000 -e100f08670c1c78b59351c33526f8d7eb4e4abeaace4bde8f8f9a65e826d905f=600260016000030460005260016000510160205260406000f300 -518779d7b59baf1ff9c3c45cff398e12ae2d88511da81ec16f9a0dd9e8b32c6d=600c600060006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f1506000516000556000600052600c60006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f4506000516001556000600052600c60006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40fa506000516002556000600052600c600060006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f2506000516003556000600052600c600060006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f1506000516004556000600052600c60006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f4506000516005556000600052600c60006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40fa506000516006556000600052600c600060006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f25060005160075500 -ff06284e0407bdc49c5eef8b55970f90a62e18cdf210a830c4f834f91a71f994=7f11223344556677889910111213141516171819202122232425262728293031326000527f333435363738394041424344454647484950515253545556575859606162636460205260406000f300 -a4cb6609f02e609855d0ae4469bc0c2dc008e0b6b77906b9622eb50e147b4a22=7f11223344556677889910111213141516171819202122232425262728293031326000527f333435363738394041424344454647484950515253545556575859606162636460205260406000fd00 -a803bfe42bdb99fe3090d66eefe6c6992f5677953c520ec7ece5b5a4b8b928db=6000357f1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201ff60005280600055806000f3 -9fb65906349b75182a0aea5e5020ca92c4bff64eba948b986bb4ba18caf322de=6000357f1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201ff60005280600055806000fd -0f73f356d63d54c487e160fe69035f674a815e71913d266052f8b5a35b4e2b64=6004356024356044356064358360005261010060006020600080855af182846101003e61c0de3b60200160008061c0de3c3660200160008037386020016000803961dead6000555050505050 -62516506325d7cd9a9c5ed8d0c534e9dde66627892fcb141a0a58814482c4d9e=60106000fd00 -52aadc0ad8118342fb956b517e52d1e9af1705ebde4526e70a7e7803d994b5f7=5b6001156013576301000000600020506000565b00 -7ff408e57e6ca4efed1ae0920cf2e2d4d01b9b11790d80fbb03e6a706145260e=600160000360002000 -05f086dcbd850473bd11208c9e821dbf8b9ebe4095edaf3aee8f6b9dd4f6b2ba=6000602435146100115760005061003b565b5a600052600060006000600060006004356175305a03f1505a602052602a60205160005103036000555b60016024351461004d57600050610075565b5a60005260006000600060006004356175305a03f4505a602052602760205160005103036000555b600260243514610087576000506100af565b5a60005260006000600060006004356175305a03fa505a602052602760205160005103036000555b6003602435146100c1576000506100eb565b5a600052600060006000600060006004356175305a03f1505a602052602a60205160005103036000555b63040000006000541161010057600054610105565b62ffffff5b60005500 -0a4b8458a53bca2e23b7be94690a4436eb6e4081d48378cf263177c4e66da62f=6160a760025500 -10391197b6d3cd7f22c044e4a904c1f7136daa5ae42fa8590879ae0d8ad4c795=610100600155600060006000600061dead6175305a03f45060106000fd00 -a34b7fbfec51c8541a6fb948321c07845a592acba08b13c14e8f8af22fedad76=610101600155600060006000600061dead6175305a03f4505b600115602b576301000000600020506018565b00 -d86c106de10d7cd27f75e873cc9c1c3fb020b5e3680122c421619a7efe7ec1d0=610102600155600060006000600061dead6175305a03f450600160000360002000 -b2d81f953c790a7e4b483d54733f2596be5c1ea4ee0f35263509fef8001bc26b=6160a76000556000600060006000600435610100015af400 -3f0007b88f06463a813b03c55b07ee91057e2bc54fc36d4dac83a7a9e1a7afd7=611000600d6000805a915061beef6000555a9050828183030384556001840193505a915063deadbeef6000555a9050828183030384556001840193505a9150600080555a9050828183030384556001840193505a9150600080555a9050828183030384556001840193505a91506112346000555a9050828183030384556001840193505a915060006001555a9050828183030384556001840193505a91506160a76002555a9050828183030384556001840193505a915060006003555a9050828183030384556001840193505a91506160a76003555a9050828183030384556001840193506000805560006001556000600255600060035550505050 -8bbed1d29403ad31bc446e9eca24e6c2fedb931f1bd387377e80b179e966ffa6=476000526000516040526021603ff3 -eb957dab28ae072ae7dcc6ed70eae55227971d7f99851ccc1be18704448a5361=4760005260206000f3 -8d95f8713c7ef660d149c2330a4ea05923319e1fad7a6acbc1804cb953f0dfbe=600435600180602061c0de3b63c0dec0de3b6160a7600052856000811461015b5760f181146101645760f281146101785760f4811461018c5760fa811461019f5761f1f181146101b25761f2f181146101c85761f4f181146101de5761faf181146101f35761f1f281146102085761f2f2811461021e5761f4f281146102345761faf281146102495761f1f4811461025e5761f2f481146102745761f4f4811461028a5761faf4811461029f5761f1fa81146102b45761f2fa81146102ca5761f4fa81146102e05761fafa81146102f55760fd811461030a5760fe81146103415760ff811461037a5760f081146103b25760f581146103d55761f0f181146103fb5761f5f181146104255761f0f281146104525761f5f281146104755761f0f4811461049b5761f5f481146104bd5761f0fa81146104e25761f5fa811461050b576460baccfa5781146105375765bad0bad0bad0600052610551565b47600052610551565b602060008060008061ca115af19550610551565b602060008060008061ca115af29550610551565b6020600080600061ca115af49550610551565b6020600080600061ca115afa9550610551565b602060008060008063ca1100f15af19550610551565b602060008060008063ca1100f15af29550610551565b6020600080600063ca1100f15af49550610551565b6020600080600063ca1100f15afa9550610551565b602060008060008063ca1100f25af19550610551565b602060008060008063ca1100f25af29550610551565b6020600080600063ca1100f25af49550610551565b6020600080600063ca1100f25afa9550610551565b602060008060008063ca1100f45af19550610551565b602060008060008063ca1100f45af29550610551565b6020600080600063ca1100f45af49550610551565b6020600080600063ca1100f45afa9550610551565b602060008060008063ca1100fa5af19550610551565b602060008060008063ca1100fa5af29550610551565b6020600080600063ca1100fa5af49550610551565b6020600080600063ca1100fa5afa9550610551565b4760005260005160005560008060008060006260bacc5af150476000526000516000541461033c57640badbadbad6000525b610551565b476000526000516000556000806000806000620600066161a8f150476000526000516000541461037557640badbadbad6000525b610551565b47600052600051600055600080600080600063deaddead5af15047600052600051600054146103ad57640badbadbad6000525b610551565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c610551565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c610551565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600080600080895af19550610551565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600080600080895af19550610551565b8160008563c0dec0de3c81846000f094506020600080600080895af29550610551565b8160008563c0dec0de3c615a1782856000f594506020600080600080895af29550610551565b8160008563c0dec0de3c81846000f0945060206000806000885af49550610551565b8160008563c0dec0de3c615a1782856000f5945060206000806000885af49550610551565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000806000885afa9550610551565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000806000885afa9550610551565b6103ff6000526020600060206000806460baccfa575af195505b508461055d5760206000fd5b836105685760206000fd5b600051600055505050505050 -e072ca4e44f39e2861bf2dd3848ae1d57d606c88ab8fb7c557287f611fce8b15=4760005260206000f3 -d230b310957a07eb653cf0f74a2f0b12b2ce777c388d2e7429a2f6f76863ee4c=47600052600051600055fe -b0bbc0608478259d03d5b37781443defa85f60926523f33ac8621c634a3f8d8a=4760005260005160005560206000fd -dddc4cdd0ce51386ddc68be5f97ae1c4f9b0be4cf052c6024934cfae9fb271fc=600035600081036013574760005260206000f35b600181036000526020600060206000806460baccfa575af160345760206000fd5b60206000f3 -dfbd09658814232694ba5dfb37d2fbb53f3be0c71ac1b5887e13b0680f394be4=60ff60005260006000602002612774015260016001602002612774015260026002602002612774015260056003602002612774015260fe6004602002612774015260ff6005602002612774015261010060066020026127740152610101600760200261277401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600860200261277401527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe600960200261277401527f8000000000000000000000000000000000000000000000000000000000000000600a60200261277401527fa000000000000000000000000000000000000000000000000000000000000000600b60200261277401527f5555555555555555555555555555555555555555555555555555555555555555600c60200261277401527faaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600d602002612774015260006000602002614e84015260016001602002614e84015260026002602002614e84015260056003602002612774015260fe6004602002614e84015260ff6005602002614e8401526101006006602002614e8401526101016007602002614e8401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6008602002614e8401527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6009602002614e8401527f8000000000000000000000000000000000000000000000000000000000000000600a602002614e8401527fa000000000000000000000000000000000000000000000000000000000000000600b602002614e8401527f5555555555555555555555555555555555555555555555555555555555555555600c602002614e8401527faaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600d602002614e84015260006020525b600e60205110156104f05760006040525b600e60405110156104e257600051600101600052631000001d60005155600051600101600052600060205160200261277401511461032f57602051602002612774015160005155610336565b6080600051555b6000516001016000526000604051602002614e8401511461036557604051602002614e8401516000515561036c565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511d60005155600051600101600052631000001b6000515560005160010160005260006020516020026127740151146103d1576020516020026127740151600051556103d8565b6080600051555b6000516001016000526000604051602002614e8401511461040757604051602002614e8401516000515561040e565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511b60005155600051600101600052631000001c6000515560005160010160005260006020516020026127740151146104735760205160200261277401516000515561047a565b6080600051555b6000516001016000526000604051602002614e840151146104a957604051602002614e840151600051556104b0565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511c600051556040516001016040526102e3565b6020516001016020526102d2565b0000 -d9dee826162f616a839ce0bfee0db9cb422a6f991c5831838d1f4142c9a3c43b=60ff60005260806000602002612774015261800060016020026127740152638000000060026020026127740152678000000000000000600360200261277401526f80000000000000000000000000000000600460200261277401527f80000000000000000000000000000000000000000000000000000000000000006005602002612774015260006000602002614e84015260016001602002614e84015260026002602002614e84015260056003602002612774015260fe6004602002614e84015260ff6005602002614e8401526101006006602002614e8401526101016007602002614e8401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6008602002614e8401527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6009602002614e8401527f8000000000000000000000000000000000000000000000000000000000000000600a602002614e8401527fa000000000000000000000000000000000000000000000000000000000000000600b602002614e8401527f5555555555555555555555555555555555555555555555555555555555555555600c602002614e8401527faaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600d602002614e84015260006020525b6006602051101561040d5760006040525b600e60405110156103ff57600051600101600052631000001d60005155600051600101600052600060205160200261277401511461024c57602051602002612774015160005155610253565b6080600051555b6000516001016000526000604051602002614e8401511461028257604051602002614e84015160005155610289565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511d60005155600051600101600052631000001b6000515560005160010160005260006020516020026127740151146102ee576020516020026127740151600051556102f5565b6080600051555b6000516001016000526000604051602002614e8401511461032457604051602002614e8401516000515561032b565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511b60005155600051600101600052631000001c60005155600051600101600052600060205160200261277401511461039057602051602002612774015160005155610397565b6080600051555b6000516001016000526000604051602002614e840151146103c657604051602002614e840151600051556103cd565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511c60005155604051600101604052610200565b6020516001016020526101ef565b0000 -4a110a25479924a086a81ca8a92aa017b797f261f6416dff9433c2ce93fbef6d=6160a7600055600060006000600060006004355af1506160a760015500 -1ea1a1dd8fd66ed2dfe3c130ae6590fe933b92c0e1c28c8d21c104b66620fb77=6000600060006000600073a0000000000000000000000000000000000000005af160005500 -d5f3cccc5baa4f1489a77f9802821d3443fcb059dad76e3d3f1f29b3caa001a0=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206103e86080600060015afa60005560a060020a6103e851066001556001543214600255600060005260006020526000604052600060605260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060025afa6003556000516004556103e851600555600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060035afa6006556000516007556103e851600855600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060045afa6009556103e851601055600060005260006103e8526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a05260206103e860a1600060055afa6011556103e85160125560006000526000602052600060405260006060526000608052600060a05260006103e8527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d460605260406103e86080600060065afa6013556103e85160145561040851601555600060005260006020526000604052600060605260006103e8526000610408527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba602052600360405260406103e86060600060075afa6016556103e8516017556104085160185560006000526000602052600060405260006103e8526000610408527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206103e8610180600060085afa6019556103e85160205500 -9587684c7d5328f4f12a5b051bd5d226074263879c6c11ae0bda0b52db7e4ef2=366000600037655a175a175a173660006000f560005500 -84e732055591f479202856ec8f623d1e658edaf7d7809222327ed8e5ffe654fa=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed6000556000356000526000600060206000600073a0000000000000000000000000000000000000005af16001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -c95eb6147c609e08130642304cc51ae275b0e820a9977983a272b34c54c78e00=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60005560006000600060006000355afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -9ea036a2ecc2d488c43c1c709066fe7c2b4a08bb40ab95a86e2a8a6c5b4c01c0=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602061200060806000600260015af100 -ad49657ad70b902dd9b0677d5b7833b0f0e83588e6cfc455a1ac9917129eb1bf=7c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600260025af100 -eb5eb639416472e142020f1e67a041cfcaf8d03a842f9c01bd89597085049d75=7c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600260035af100 -8229242bf1fde9040f2f396ee2a1b987438811e5e5005cbcab281d5041a4c962=7c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600260045af100 -7426d3b5746a93100d741da990638c6b7f7cf02a67dab9a69a0f7cf09a0928c7=6001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a052602061200060a16000600260055af100 -cd6179f0a65f4246fd10b7212d395502415ca6076ea088ea3c8e94c1707b9fe7=7f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d4606052604061200060806000600260065af100 -a5fd552973e23abd9024bf8412ce25ae9c29d970146f929cb0cad298a8f29615=7f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020526003604052604061200060606000600260075af100 -112917d8c4616c52b1409fa4c4b68f40c0d692d46980d727901a158c458ad973=7f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206120006101806000600260085af100 -8f1154bfbac5fd067c557a227185f40ffcce358aafb06e90bec9c0aeb7474a99=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed6000553660006000373660006000f06001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -4b8086243146fa9008248cd0d1a2bc488005f32f793f25a31c159a93bb514f37=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed6000556000600060006000600073b0000000000000000000000000000000000000005af1507ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60015500 -a7b95cbf5827efe70bc6de71fadd07cec971227e581dce759a09b6343a722828=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60005562012020620a00006000600073a0000000000000000000000000000000000000005afa507ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600155620a000051610a0055620a110051610a1155620a010051610a0155620a120051610a1255620a020051610a0255620a130051610a1355620a030051610a0355620a140051610a1455620a040051610a0455620a150051610a1555620a050051610a0555620a160051610a1655620a060051610a0655620a170051610a1755620a070051610a0755620a180051610a1855620a080051610a0855620a190051610a1955620a090051610a0955620a200051610a2055620a100051610a105500 -3be0f9628c2a23d54ff633103257d0defddee2a78dac6362694a32ae88524c1e=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602061200060806000600060015af1620a00005260a060020a6120005106620a010052620a0100513214620a02005260006000526000602052600060405260006060526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060025af1620a030052600051620a04005261200051620a05005260006000526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060035af1620a060052600051620a07005261200051620a08005260006000526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060045af1620a09005261200051620a10005260006000526000612000526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a052602061200060a16000600060055af1620a11005261200051620a12005260006000526000602052600060405260006060526000608052600060a0526000612000527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d4606052604061200060806000600060065af1620a13005261200051620a14005261202051620a15005260006000526000602052600060405260006060526000612000526000612020527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020526003604052604061200060606000600060075af1620a16005261200051620a17005261202051620a1800526000600052600060205260006040526000612000526000612020527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206120006101806000600060085af1620a19005261200051620a20005260006120005262012020620a0000f300 -96d286f562b996dce5062cad0a9c13b57edc86ac8505797641f7e1e76fd3eb93=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055366000600037655a175a175a173660006000f56001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -d9ee1ed86455c4d7ca5c8734f327a0cd55d4b62cf74dc98cc5bda96e1bd7d4fe=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60005562012020620a00006000600073a0000000000000000000000000000000000000005afa507ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600155620a000051610a0055620b000051610b0055620a010051610a0155620b010051610b0155620a020051610a0255620b020051610b0255620a030051610a0355620b030051610b0355620a040051610a0455620b040051610b0455620a050051610a0555620b050051610b0555620a060051610a0655620b060051610b0655620a070051610a0755620b070051610b0755620a080051610a0855620b080051610b0855620a090051610a0955620b090051610b0955620a100051610a1055620b100051610b1055620a110051610a1155620b110051610b1155620a120051610a1255620b120051610b1255620a130051610a1355620b130051610b1355620a140051610a1455620b140051610b1455620a150051610a1555620b150051610b1555620a160051610a1655620b160051610b1655620a170051610a1755620b170051610b1755620a180051610a1855620b180051610b1855620a190051610a1955620b190051610b1955620a200051610a2055620b200051610b205500 -0234fd7879d6486d237da0c6030340a887a320ad8d126a6daf76c9ba5611f6c5=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602061200060806000600060015af2620a00005260a060020a6120005106620a010052620a0100513214620a020052600061200052602061202060806000600160015af2620b00005260a060020a6120205106620b010052620b0100513214620b02005260006000526000602052600060405260006060526000612020527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060025af2620a030052600051620a04005261200051620a050052600061200052602061202060206000600160025af2620b030052600051620b04005261202051620b05005260006000526000612020527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060035af2620a060052600051620a07005261200051620a080052600061200052602061202060206000600160035af2620b060052600051620b07005261202051620b08005260006000526000612020527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060045af2620a09005261200051620a100052600061200052602061202060206000600160045af2620b09005261202051620b10005260006000526000612020526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a052602061200060a16000600060055af2620a11005261200051620a120052600061200052602061202060a16000600160055af2620b11005261202051620b12005260006000526000602052600060405260006060526000608052600060a0526000612020527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d4606052604061200060806000600060065af2620a13005261200051620a14005261202051620a150052600061200052600061202052604061300060806000600160065af2620b13005261300051620b14005261302051620b15005260006000526000602052600060405260006060526000613000526000613020527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020526003604052604061200060606000600060075af2620a16005261200051620a17005261202051620a180052600061200052600061202052604061300060606000600160075af2620b16005261300051620b17005261302051620b1800526000600052600060205260006040526000613000526000613020527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206120006101806000600060085af2620a19005261200051620a20005260006120005260206120206101806000600160085af2620b19005261202051620b20005260006120205262012020620a0000f300 -9a1120d19b7b2d1202e5a11ef1f37a1929c670177e16beaf188df19cfc106570=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055366000600037635a175a173660006000f56001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -0ffa096238cc2e0df9e4cde0ef0b7a82a0362a1ce80056ab959597e365da4fd0=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206120006080600060015af4620a00005260a060020a6120005106620a010052620a0100513214620a02005260006000526000602052600060405260006060526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206120006020600060025af4620a030052600051620a04005261200051620a05005260006000526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206120006020600060035af4620a060052600051620a07005261200051620a08005260006000526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206120006020600060045af4620a09005261200051620a10005260006000526000612000526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a052602061200060a1600060055af4620a11005261200051620a12005260006000526000602052600060405260006060526000608052600060a0526000612000527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d460605260406120006080600060065af4620a13005261200051620a14005261202051620a15005260006000526000602052600060405260006060526000612000526000612020527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba602052600360405260406120006060600060075af4620a16005261200051620a17005261202051620a1800526000600052600060205260006040526000612000526000612020527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa610160526020612000610180600060085af4620a19005261200051620a20005260006120005262012020620a0000f300 -2a203f69a317afd0cdf2dd1ca84a097da8a0cdda385e87a53540eee36596e3b3=7f6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9600052601b6020527f79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986040527f6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a96060526020600060806000806001620f4240f1600055600051600155 -5384e137990f962e727fc9208c6ddae5eebed3c50907b8580f1cb88ee887d156=6001600152600160016001f060025500 +c768c173e76aa9afafc358f1faa7a441e93dc31af52f01496d7743b21d8d9bf0=60243560443560043562c0de000160005b6000811415603157600060006000600060008689f1905082840193505b6010565b82840360005550505050 +850489727f49e4d0fbf69f704aa27e6ae870c65eeeecaf1ee989968fa94168e5=60005b6101008110156033578060981b6000600060006000600085612710f115602757600182555b505b6001810190506002565b50600161010055 6928d085b75273e089cb60e6279c2e5258b5de474c5c739efcda1d2f9e82ea5b=600060006000600060003562011170fa60015500 +5384e137990f962e727fc9208c6ddae5eebed3c50907b8580f1cb88ee887d156=6001600152600160016001f060025500 3e3ca66c03e0afded22a1454fa2e937382c62708046cbdb213e599ccd49d0c08=60406000604060006000731000000000000000000000000000000000000001611770f100 bb647378cad07f6e87fe40bb0fe78701a9e3661a5362fa59bda7c3957db6cfb6=60406000604060006001731000000000000000000000000000000000000001611770f160005500 -88456889c166b83101ad56e52b749cee36c47f971234d3bb2192f65909f7d3ab=600160025533600455346007553060e6553260e8553660ec553860ee553a60f05500 -5bd15877907e4de9273ea001e7f4a96dddbe0510b3342aafecd9bdf97edeec92=604060006040600060027310000000000000000000000000000000000000026203d090f160015500 a3ca55d78a4ac1b3d171e8d3174126d734a02985e10c202967d8ced5b26adfce=6040600060406000600173100000000000000000000000000000000000000162055730f160005500 -8e3b63e1835877f5c7e14ae041df5e55c3e1c58425c48ee09d567c25afd345c5=6001600255622fffff60002000 +5bd15877907e4de9273ea001e7f4a96dddbe0510b3342aafecd9bdf97edeec92=604060006040600060027310000000000000000000000000000000000000026203d090f160015500 +88456889c166b83101ad56e52b749cee36c47f971234d3bb2192f65909f7d3ab=600160025533600455346007553060e6553260e8553660ec553860ee553a60f05500 8ed43c0dd7c55dd8e69ca219d4e46f648a1a8822c54a706dc6827a2df2b12d26=60406000604060006000731000000000000000000000000000000000000002614e34f16001556001600b5500 12c5b66cab03697243c3c8394e393d9ada028aa2f939a29893dd29132cb251ab=60406000604060006000731000000000000000000000000000000000000001620249f0f160005500 -14b4e2df05d9e705d07cbe82e401ae12f456777e33684246ba685a82b999db2f=60406000604060006014731000000000000000000000000000000000000001620c3500f160005500 +8e3b63e1835877f5c7e14ae041df5e55c3e1c58425c48ee09d567c25afd345c5=6001600255622fffff60002000 b77a8cb081a384fefe0b039719a385c5e7826d5fdb3503cda50dcb1169f029ed=6040600060406000600a731000000000000000000000000000000000000002620927c0f16001556001600b5500 -0e02fd4a9d353d6f8b41c307719a12a96d40df3a8017deb600b3be18a9815da1=6040600060406000600073100000000000000000000000000000000000000261c350f1600155731000000000000000000000000000000000000000ff00 +14b4e2df05d9e705d07cbe82e401ae12f456777e33684246ba685a82b999db2f=60406000604060006014731000000000000000000000000000000000000001620c3500f160005500 f07eabab66fdff9b2221467aa50e4adb2fa9752be1569992c09b58afc9186fde=600160025500 -cb98cd24b0233d3b9df91efc03eb40eb74fa5fda19002137f3c3b2fd828e069c=60406000604060006002731000000000000000000000000000000000000002620493e0f160015500 -cd28eb7e8e982cc57daf0ebef75bb87c5a1db046d0d0807ebd05bde76a3e12da=604060006040600060037310000000000000000000000000000000000000036203d090f160025500 +0e02fd4a9d353d6f8b41c307719a12a96d40df3a8017deb600b3be18a9815da1=6040600060406000600073100000000000000000000000000000000000000261c350f1600155731000000000000000000000000000000000000000ff00 7813f04a6d80c2325ce2651c237631d8e8a4afc30418ed83cdcaf7e6579969d2=600160035533600455346007553061014a553261014c55366101505538610152553a6101545500 -8b918c7081972ad7b1410972e6a04b99afeda6e9b41f30b5e7b5e360f2196b6e=6040600060406000600073100000000000000000000000000000000000000362061a80f16002556001600b5500 -f2cdbcd1dc78c4f263d22b40356f172af8a68747e742ef5412a84aa63f620353=60406000604060006000731000000000000000000000000000000000000001620c3500f160005500 +cd28eb7e8e982cc57daf0ebef75bb87c5a1db046d0d0807ebd05bde76a3e12da=604060006040600060037310000000000000000000000000000000000000036203d090f160025500 +cb98cd24b0233d3b9df91efc03eb40eb74fa5fda19002137f3c3b2fd828e069c=60406000604060006002731000000000000000000000000000000000000002620493e0f160015500 3577c21f368308f65d37ab7fd52ca073e89f8de1acbed04abac4b9f3d6093e4f=60406000604060006000731000000000000000000000000000000000000002620927c0f160015500 +f2cdbcd1dc78c4f263d22b40356f172af8a68747e742ef5412a84aa63f620353=60406000604060006000731000000000000000000000000000000000000001620c3500f160005500 +8b918c7081972ad7b1410972e6a04b99afeda6e9b41f30b5e7b5e360f2196b6e=6040600060406000600073100000000000000000000000000000000000000362061a80f16002556001600b5500 3c8f41896e16cadb4206f2d760dd083207e2735bc8e9e240aa41a2cc6163af37=6001600355622fffff60002000 +f5c742a5ab1925c82083c4dee955d0c814e53920968aa92b59b0c8d1fcdeb360=60406000604060006000731000000000000000000000000000000000000002620927c0f1600155622fffff60002000 c954d7752af9bb6b359ec69b4f1b7b5d8496b1b1c7a5e5eb1bf0e5ce1b08a0ad=6040600060406000600073100000000000000000000000000000000000000362061a80f160025500 c43df18b56f764adfe86e2d2a48e33b927d48bed4522c2aabe28115c550e4838=60406000604060006000731000000000000000000000000000000000000001620c3500f16000556001600b5500 -f5c742a5ab1925c82083c4dee955d0c814e53920968aa92b59b0c8d1fcdeb360=60406000604060006000731000000000000000000000000000000000000002620927c0f1600155622fffff60002000 ce2a353f90f2d01731989db0ecffe7d87aaf7a4fef740d3450d85d46e9c2c6f5=600160035500 7bccf87f855ed3aa795c0985150e4c4f002eb570aa34a94ab98e7136a194e4c4=60406000604060006000731000000000000000000000000000000000000002620927c0f16001556001600b5500 79e1d0c4625fa2858058c76337db79abc512f3eee48e7350ddcc566944b59240=622fffff600020506040600060406000600073100000000000000000000000000000000000000362061a80f160025500 +67b61ae1d5635fbd4412ec9b2c60a1418a290151e86ab16c497ec6acd8a79a9a=6040600060406000600073100000000000000000000000000000000000000361c350f1600255731000000000000000000000000000000000000001ff00 d9062174eb6c02dc75092567cdb85a07d131f321f6233583c1aca93c7ea8b771=600160035500 c4b27aecda668677fbf62f8e3015c4456eb92e4d6cb80501135c8e8b5efafd62=60406000604060006000731000000000000000000000000000000000000002620186a0f160015500 -67b61ae1d5635fbd4412ec9b2c60a1418a290151e86ab16c497ec6acd8a79a9a=6040600060406000600073100000000000000000000000000000000000000361c350f1600255731000000000000000000000000000000000000001ff00 1a243e537a1f1194ca38645e48c62d8772c1e0f3d18d80e49ef32b6704765a89=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f160025500 -f72666efbda95799975b0e9fb2cd7271b921758f61f87fb96f8ecb79498b074c=604060006040600060007310000000000000000000000000000000000000016207a120f160025500 75b5d0815b5a203505379176aa93a9b92f4991c54ec9bcb3a920c822926a4b9d=6040600060406000600073100000000000000000000000000000000000000163017d7840f160005500 e31f2dd3719ab6b5665d781a415fb9676b6d8564f72b34cbe2e62a14f12fced6=60406000604060006000731000000000000000000000000000000000000002620f4240f160015500 +f72666efbda95799975b0e9fb2cd7271b921758f61f87fb96f8ecb79498b074c=604060006040600060007310000000000000000000000000000000000000016207a120f160025500 b51f7a5fde1b616abd9108bd69188022c9a3a8ecdb2cc1b10fbe56c2de4a547b=600160035533600455346007553061014a553261014c55366101505538610152553a6101545500 f8b7a672693c1238a852f75319baa0ebddcbfb7f1ed66a9be6df5eb9b4e64ab0=604060006040600060037310000000000000000000000000000000000000036203d090f260025500 aab9b0b3c96ec228ad35203f938704da71856552d8ccd462c32b6763888eff32=6040600060406000600073100000000000000000000000000000000000000362061a80f26002556001600b5500 @@ -1531,26 +1270,26 @@ cbc8787a9c2f2999deac8496bc4c0fce7586384b86a424e3db005b59887af28e=604060006040600 dc572586bef4a8aaeddeca7bdb4a2fb22aea11e73c3a0c8257922ad35da9ba48=60406000604060006000731000000000000000000000000000000000000002620186a0f260015500 5eeff94fbf1224f83abf924923d427f2c5117e826dc41d97eb722afcb98d7861=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f160025500 f73554dec3a16f0e74e40e1024a0ef5ec5d54e5031b36135bc5a29dd18a3fe9e=60406000604060006000731000000000000000000000000000000000000002620f4240f260015500 -0ef4264a4c2eefe075f63a398275b2b78610a719d84b860ab74daf174631ba35=60406000604060006000731000000000000000000000000000000000000001620c3500f16000556001600b5500 57e6584d10e091b11b7080febb7b0d44cebe2e2dec85ed7af2afc7e47f3fe058=6040600060406000600073100000000000000000000000000000000000000362061a80f260025500 +0ef4264a4c2eefe075f63a398275b2b78610a719d84b860ab74daf174631ba35=60406000604060006000731000000000000000000000000000000000000001620c3500f16000556001600b5500 5c4c27068d91a4bc0a509b062587e32c76d219f8c6383de4618a5083a54b9b5a=622fffff600020506040600060406000600073100000000000000000000000000000000000000362061a80f260025500 046362e811154a462291783b0bce2d041eebd98be82f44a641ee7841b0149a06=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f260025500 +5c4e4211d31ab5f57365c6e4c7984034fd67bba3f8fdc2d8b619ad44f84a6785=604680602760003960006000f0600a5560406000604060006000600a54620186a0f2600b5500fe604060006040600060007313136008b64ff592819b2fa6d43f2835c452020e620186a0f2607a5560128060346000396000f300fe600160005530601455326015553360165500 0781c07e53700dd3d72727c8b2debce4508ab04080c0f18a391d94ee9a6354ad=60006000600060006000600035620c3500f100 ffb08aeffbd9b520533cfc3c107a95d2a60ae17609070190257a7cc3c3a3162c=7f604060006040600060007313136008b64ff592819b2fa6d43f2835c452020e626000527f0186a0f2600b5533600c55000000000000000000000000000000000000000000602052604060006001f000 -5c4e4211d31ab5f57365c6e4c7984034fd67bba3f8fdc2d8b619ad44f84a6785=604680602760003960006000f0600a5560406000604060006000600a54620186a0f2600b5500fe604060006040600060007313136008b64ff592819b2fa6d43f2835c452020e620186a0f2607a5560128060346000396000f300fe600160005530601455326015553360165500 +b632e6ffcaeaba9e194657cee1302cad3b6f20080074d6b676eec1c3ce52830c=604880600f60003960006000f000fe6000601f80602960003960006000f5600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 +9317b5ce007832961b43b36beec35b6eb98061807bb791ba6a57599a48c50422=604680600f60003960006000f000fe601f80602760003960006000f0600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 a1600b2bec3bcf1f10142fd2693965b831337028896de7a65b0ec5e3c1b05485=601f80602760003960006000f0600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 e8b1ae01b050389d43a28f95b9772586231d88a54f96a951174feb63ed78d6e5=6000601f80602960003960006000f5600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 -9317b5ce007832961b43b36beec35b6eb98061807bb791ba6a57599a48c50422=604680600f60003960006000f000fe601f80602760003960006000f0600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 -b632e6ffcaeaba9e194657cee1302cad3b6f20080074d6b676eec1c3ce52830c=604880600f60003960006000f000fe6000601f80602960003960006000f5600a5560406000604060006000600a54620186a0f2600b5500fe601280600d6000396000f300fe600160005530601455326015553360165500 17a17bdfd8ed20c2d05b070e39b9860be846caecdb1a6c1593d5e4de63d001a2=60406000604060006103e873945304eb96065b2a98b57a48a06ae28d285a71b561c350f260005500 b43dc61de74fe6a4953f2906b071ec1438c398373f3a9698f1fe18aa0978264a=6000602d80601160003960006000f500fe600060006000600060017310000000000000000000000000000000000000016207a120f2600155600160025500 -61100d03e6bc8e21007b967394c28070e1a33b8251653d33f33bc844f795e18c=602d80600f60003960006000f000fe600060006000600060017310000000000000000000000000000000000000016207a120f2600155600160025500 9ac432d14151579f379e6c6ef6603dba2c74f9ca0b72aa1ddd8ab6b447e588b0=60006000600060006000600035620493e0f100 +61100d03e6bc8e21007b967394c28070e1a33b8251653d33f33bc844f795e18c=602d80600f60003960006000f000fe600060006000600060017310000000000000000000000000000000000000016207a120f2600155600160025500 9d0234cabda87e4cee52a8399e41e5d14a66ea152f45ff4cbc3f28b0ed90afc7=602880600f60003960006000f000fe600060006000600060017310000000000000000000000000000000000000016207a120f260015500 3e66e2480ca9e491f8eda2b3fea9454f246a77f7230c37b0f00ec43bac018405=6000602880601160003960006000f500fe600060006000600060017310000000000000000000000000000000000000016207a120f260015500 d4cc8a95f1e80db2ba9a385019262bab72dad70d36552b7ce4eeb2af6a255c7f=600160025500 -3055ea3fb0023a093dc69ca6f68d42a1bf1f4aeb9e72345bc724cc1fde2f99d3=602780600f60003960006001f000fe6000600060006000600173100000000000000000000000000000000000000161c350f260015500 c26c1be026f10f7967f44e293e60a5f0792a00930b69ea74b536e6a95f46817a=6000602780601160003960006001f500fe6000600060006000600173100000000000000000000000000000000000000161c350f260015500 +3055ea3fb0023a093dc69ca6f68d42a1bf1f4aeb9e72345bc724cc1fde2f99d3=602780600f60003960006001f000fe6000600060006000600173100000000000000000000000000000000000000161c350f260015500 b574c885f9a99c244236f9e0cff1c5f8a6384b7a5a12e193dd4c2470779b7801=7f6040600060406000600573945304eb96065b2a98b57a48a06ae28d285a71b5626000527f0186a0f260005500000000000000000000000000000000000000000000000000602052604060006005f000 d8afdb839931d006b01476af545bf36e997c21212cd1080ec45b76fb7a401349=60406000604060006000731000000000000000000000000000000000000001620f4240f1505860035500 c1fb2cafa472d25b2e701f98e55b581704134654e4acb7b37071cc4dee227d02=600160005500 @@ -1569,8 +1308,8 @@ a5d087f7adfc731570eee3539bc467fb25b9f6a19bf16d9da03b599f0d2c337a=600160005401600 237ff310e455a73a4d07aad6012487728223d10f5d49ab1c404e57afd2da9221=6001600054016000556000600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b610401600054046001036127105a0302f16001556103e86000540260010160025500 9776b831972d57734e2df2871301f9ca8c6b54d6c42ee92c07e2b3bf727a66b0=6000600060006000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffff16002556000600060006000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffff16003556001600054016000556000600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff160015500 c650386e5e3f7f09afe65aa27227810f408e2c2885c9dda7c29a41d6f15061d2=6001600054016000556000600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b620186a060005402600101f16001556103e86000540260010160025500 -c431b3d79aac24cff8d4bead63dcc67fc68d66634da743c4641e61c27a7655b3=6000600060006000601773bad304eb96065b2a98b57a48a06ae28d285a71b5620186a0f1506000600060006000601773945304eb96065b2a98b57a48a06ae28d285a71b56707fffffffffffffff100 f74ed00d64c6231ed6fd7aabeb3a099965a181c932db60371f3256f591c5c28d=600160005401600055600060006000600060003062036b005a03f160015500 +c431b3d79aac24cff8d4bead63dcc67fc68d66634da743c4641e61c27a7655b3=6000600060006000601773bad304eb96065b2a98b57a48a06ae28d285a71b5620186a0f1506000600060006000601773945304eb96065b2a98b57a48a06ae28d285a71b56707fffffffffffffff100 69b590bf3db76b10d8abe63262f23b518e99727fd14b1f6033887ab8f919a8cb=600160005401600055600060006000600060005473bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff260015500 8d8cc3a8ee3851b8ba74ab18bd08aeda6de52b564e792ffd482a70080a72fb43=6001600054016000556000600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b610401600054046001036127105a0302f26001556103e86000540260010160025500 1c0dff43465a585b21712318c2c0031150fc5fe49bc4bc158c161bbc58fb1fcd=6001600054016000556000600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b620186a060005402600101f26001556103e86000540260010160025500 @@ -1593,23 +1332,23 @@ b6907b94d070d2947662ab7e7598594c4b4bb454df640bb9930390e22a653d99=600160006000600 f88565896c3b7e5e9e99e948b5886cca65a3da35d5d0a4f0b102818316f124ac=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600a600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d87620249f0f25060005160005500 2fd72243d8f89ed7a7412e1406275bba1aad6620bc8e75cff8c78b2164cf6e66=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600260006040600068056bc75e2d6310000073945304eb96065b2a98b57a48a06ae28d285a71b56bfffffffffffffffffffffffff260005500 2f13e7be39a3ba95a686532c8dc9a985484a3dbab82150afcadbc4ec9178a6df=6002600060406000670de0b6b3a764000173945304eb96065b2a98b57a48a06ae28d285a71b561c350f260005500 -61839ff6dd838c9c6659c31d176a290193231fb954f7d7281566bd393774d1d9=600160015500 ba281882f33f7d12cbc50e958f98fdeb4caa08b617296032f29a5e7f7298f29f=6040600060406000600073100000000000000000000000000000000000000161c350f100 +61839ff6dd838c9c6659c31d176a290193231fb954f7d7281566bd393774d1d9=600160015500 8ade62cf78cdedb39e01a32c86d579f50259b6210ee1e328eedb7e30e7b35a95=6460016002556000526005601b670de0b6b3a7640018f0ff00 08cff7abc9fe025eebc499241eecf9ba72f1afeda192bd1b1db17eb8c5075800=6361ffff566000526004601c6001f0ff00 ec694004735c0b522f8a9f6fd5180a9c2494247b555610be80fdc4d75b2500ac=6056600053600160006001f0ff00 6e11f3e395588cc86b63e3c2b2516f87b48c6bdb06b08687133485406879f9f4=7f6103ff6000525b7f0102030405060708090a0102030405060708090a010203046000527f05060708090a0102600160005103600052600051600657000000000000000000602052604060006001f0ff00 c137a7179c74a03d14fd503f963426b55c96d8bf1cbdc9ad3d1a36cf802d0f24=6001600053600160006001f0ff00 a32a49add76b1a0489253be706b5e8dab6df23601f8b163137f9357c99706ea7=60f4600053600160006001f0ff00 +84ce02ddd7aaf18251de022973d16da57a66afb8540bc8ac823d150f61f04580=60f9600053600160006001f0ff00 aee27f8ef4805828008cb931a22fcfdc7b29f5fa6cb059fafbde54ee908bffe3=6000600060006000600073100000000000000000000000000000000000000062061a80f16000556000600060006000600073200000000000000000000000000000000000000062061a80f1600155600160025500 746af2369d7b396e4bd872828720e3ee44a32ddc257a721d6b9fa6d15674d952=60f96000536000600160006001f5ff00 -84ce02ddd7aaf18251de022973d16da57a66afb8540bc8ac823d150f61f04580=60f9600053600160006001f0ff00 f2be3b0fb39e23bdb60c9755a02f1abd00f5dbbf3e9a9ecf28b723de274ea981=600d80600f60003960006001f000fe6001600155622fffff60002000 3cc19bd67be0e03b590c3914a7888fc7bfe26f68890764c19dcc5446a5fa0e23=605a600053600160006001f0ff00 f49c3ea625a65ef58ed794f61b60b0ae0b0cb7350dcea10506dca6a7046603fd=7f6001600155601080600c6000396000f3006000355415600957005b602035600060005260356020536055602153602260006017f000 240cceee43253699aea20e3e83707e9cd84da2a18e53d9b801886906fac74b24=7c601080600c6000396000f3006000355415600957005b60203560003555600052601d6003670de0b6b3a7640001f060005500 -398cd6796959872c403ed50ad5d3dbebe0a99c5e0fc2842540e7afdc024bb2a2=600160035533600455346005553061014a553261014c55366101505538610152553a6101545500 51d10086c257a98329b0add6e29cb76177d582c784780c9bc85d46094a267d2b=60406000604060007310000000000000000000000000000000000000036203d090f460025500 +398cd6796959872c403ed50ad5d3dbebe0a99c5e0fc2842540e7afdc024bb2a2=600160035533600455346005553061014a553261014c55366101505538610152553a6101545500 1af2def18495e5fa4ad47ed64ba29d322587f9ae8ae842697c3f9eb782943812=604060006040600073100000000000000000000000000000000000000362061a80f46002556001600b5500 f29f2b9f024abf0877bf09b16d0f902378512cdb21351f2cafdb3221b8e98355=60406000604060006000731000000000000000000000000000000000000001620c3500f26000556001600b5500 02a99c1e93cd900f2936fcc2847d8104318e36af498a1b45d2552faf8be77064=604060006040600073100000000000000000000000000000000000000362061a80f460025500 @@ -1621,9 +1360,9 @@ c0f7ed0d8e02ed57c41436dab38b36ad26350dba91ca4f37c58ea8437ed57dc7=604060006040600 cf702121818e2231130dd688ad9f774dc418a4cb117b62958855ef7b71a217e3=600160025533600455346005553060e6553260e8553660ec553860ee553a60f05500 159206c712451985f130b9eca80a8383d0011c8de790db7be4ce55e5d1bda864=6040600060406000731000000000000000000000000000000000000002620927c0f46001556001600b5500 c35f50164dd0b05b29e015b62358a090ea77f334fe41aa8f97da6034f9e8c305=604060006040600073100000000000000000000000000000000000000261c350f4600155731000000000000000000000000000000000000000ff00 -88eab4bd2174b26ebbf11ef85aff5de1c77e79292004dee2ea85e6a00d566c7a=6040600060406000731000000000000000000000000000000000000002620493e0f460015500 -2ad9bcd6417058afe68fdaa03098e2b5acf03dc1fca6c59b2a737a8ed698059b=604060006040600060027310000000000000000000000000000000000000036203d090f26002553360055500 d2095106e49e36d21f7392fedf4690153d3ebda1654e56ffa1a4fc2201abc429=600160035533600455346006553061014a553261014c55366101505538610152553a6101545500 +2ad9bcd6417058afe68fdaa03098e2b5acf03dc1fca6c59b2a737a8ed698059b=604060006040600060027310000000000000000000000000000000000000036203d090f26002553360055500 +88eab4bd2174b26ebbf11ef85aff5de1c77e79292004dee2ea85e6a00d566c7a=6040600060406000731000000000000000000000000000000000000002620493e0f460015500 d7d9ebb58870cae24949ef5e9077cb1d7f4f86b93fc7e76370c2c0855c158156=6040600060406000731000000000000000000000000000000000000002620927c0f460015500 3a0c79acef60d052ce3524576eec73bb49573b7b0d96dc31811a4dbecbf8727a=6040600060406000731000000000000000000000000000000000000002620927c0f4600155622fffff60002000 47b71b42a05f88499a250e5d3d0cc183b251591d277615c440f59f24d2354d5c=6040600060406000731000000000000000000000000000000000000002620186a0f460015500 @@ -1636,8 +1375,8 @@ b512dd9e6d8c4407956a32fb9b294ffe741000025a2a30b6d95443ec4d794fba=731000000000000 f80639dcae440a5f3755817c73200108d10346d1b2a1ec462d3c64baf147be39=604060006040600073100000000000000000000000000000000000000162055730f460005500 104c137733c8008766e33f46ed1ca976a471001b1acd32fb8ae21c0d6a2b3966=6040600060406000731000000000000000000000000000000000000001620c3500f460005500 a0d6cac9b13007bde698284e9d71776d04aeb0e83af14f6471178303416e13c7=6040600060406000731000000000000000000000000000000000000001620249f0f460005500 -57254510d94ba0bb062a4c74cfbcac305796ebb501a9e8a0eaeb0d1e8b974532=600160035533600455346006553061014a553261014c55366101505538610152553a6101545500 3a7e5951bd41fe60f89934b73f2f9feacd129886a864bebaa310f008cd6ba7c1=60406000604060006001731000000000000000000000000000000000000002620493e0f26001553360055500 +57254510d94ba0bb062a4c74cfbcac305796ebb501a9e8a0eaeb0d1e8b974532=600160035533600455346006553061014a553261014c55366101505538610152553a6101545500 d20b8c7aac7af042709438df0c55c9eb4a0c76ed138feebad265a24d4dd108a9=604060006040600060027310000000000000000000000000000000000000036203d090f260025500 0d33be7d29a18dfbea4bb5ed93a8c5ab3e109aaa0f7cbaf62a823063be027318=6001600355622fffff60002000 05d1fdcfa91cc161f56f0552e0ef4f4dfed7c9d8d4ccb4f56c91ef3858704d7a=6040600060406000731000000000000000000000000000000000000001620c3500f46000556001600b5500 @@ -1650,27 +1389,79 @@ a76fd25a630aca59f9dbe15d7d0dce26ca43500836bebbca026fbfdf43f3fc73=622fffff6000205 a567180a70bc673a59f8f8e49ba69ca22bc4f838057e1009caaeab6bb8460679=6040600060406000731000000000000000000000000000000000000002620927c0f46001556001600b5500 2348299916589fa7f254f1cff359d879e8673913e7e7bb6bf4d0ef091d8ad4da=604060006040600060017310000000000000000000000000000000000000036203d090f26002553360065500 71ef30f3f51ff455664558182375a47511db42b75352c146ae22d50d6328ccf1=6040600060406000731000000000000000000000000000000000000002620493e0f46001553360055500 -322b01b11fd871b06d0a3e5e44e351652d6111ee4bf1840eec712cb2af1d221f=60406000604060006001731000000000000000000000000000000000000002620186a0f160015500 a0d25ad83bce8d5ccc1266a7390006c141f50d55dbfa58ccaf97c9279f5f3f95=6040600060406000600273100000000000000000000000000000000000000361c350f2600255731000000000000000000000000000000000000001ff00 +322b01b11fd871b06d0a3e5e44e351652d6111ee4bf1840eec712cb2af1d221f=60406000604060006001731000000000000000000000000000000000000002620186a0f160015500 3e8a533298cabe94a8ebe2bf54b99da2b6c941b96da972ac0630bd88f6114cd2=60406000604060006000731000000000000000000000000000000000000001620c3500f16000556001600b5500 a5f9917621aa3c9aa7a9960bc14036a51d86172218f77e1a67eea6c8fffb02a8=6040600060406000731000000000000000000000000000000000000002620927c0f46001556001600b5500 4d64baf66cc6d9d0dd3475fd3615b39a15308a74f19d1a2850cba310a3397aa9=604060006040600060027310000000000000000000000000000000000000036203d090f16002553360055500 7393600193654230e2045d30a614f74a499650cc202a7439cdaf0db78f67b701=6040600060406000731000000000000000000000000000000000000002620927c0f46001556001600b5500 -1edb4454c5c39aa6e23260046157dba37e2b48f7a37cd1fa2f5c3768ac16f235=600160025533600455346007553060e6553260e8553660ec553860ee553a60f05500 2a8c48db3cd48b654c4826fb06db713f48123aac882693cc5461d82fabe81ee7=604060006040600060017310000000000000000000000000000000000000026203d090f160015500 -4a30d44b30c21f2b3213ebc5549ee0253178486a874ba9c9afdc3f999c1ca120=604060006040600060027310000000000000000000000000000000000000036203d090f160025500 +1edb4454c5c39aa6e23260046157dba37e2b48f7a37cd1fa2f5c3768ac16f235=600160025533600455346007553060e6553260e8553660ec553860ee553a60f05500 e4d99bb09a1622904a65f60c72b1c9ef57ee9e92738b91977d4bfaa645ee07f8=60406000604060006001731000000000000000000000000000000000000002620493e0f16001553360055500 +4a30d44b30c21f2b3213ebc5549ee0253178486a874ba9c9afdc3f999c1ca120=604060006040600060027310000000000000000000000000000000000000036203d090f160025500 832b3f9c132356394daddb9475fa7914249bf41fa567c1e91835050db6a7f2b0=60406000604060006001731000000000000000000000000000000000000002620493e0f16001553360055500 937af60a3bbebb327cccf02e219a1c9e91a927555238869c6e41f5cb8c275fd7=622fffff60002050604060006040600073100000000000000000000000000000000000000362061a80f460025500 4ba903617e999dc3428cdb258fecfdf2b29dcc9c8b42f173da4f1957fb3df070=604060006040600060017310000000000000000000000000000000000000036203d090f16002553360065500 8ea5f414eaee179335af56aaa0301a02c78a8f1be417758776ac2d319eaacafa=4660015500 d6f6c2b3d15ea8de99213966d762fb488bd20a2c536de50bd5add1d342b25960=61123460205260406000600073eeef5374fce5edbc8e2a8697c15331677e6ebf0b3c60005160005560205160015561567860605260406000604073a94f5374fce5edbc8e2a8697c15331677e6ebf0b3c60405160025560605160035500 8a4cd2fde1ab95e5f6b7f1d175682bf9393eec6878449795d82777be9d1b7673=6002600a600173bbbf5374fce5edbc8e2a8697c15331677e6ebf0b3c6000516002556002600a600173cccf5374fce5edbc8e2a8697c15331677e6ebf0b3c6000516003556002600a600173dddf5374fce5edbc8e2a8697c15331677e6ebf0b3c6000516004556002600a600173eeef5374fce5edbc8e2a8697c15331677e6ebf0b3c60005160055560c8600a600173eeef5374fce5edbc8e2a8697c15331677e6ebf0b3c60005160065500 +a26bb885494e0b85f27e61d59f8f645aeaea0a42b03b4d6f2c9e327989f55816=38600155303b60025500 +43a2044718bbc63caf58b8787e580d53758357db8f9a1dd83f6dec4fd5ebda3a=60003560005260003660006000f56000556001600155 +b3ae2ca19746076634f6ce2073cefb64cdc7ae3dd306639840eebdb9ea882f00=6160006000f3 +c44968378b56fe928db69677e9f50d18fdf6ae558b6afa25ecb473ab38558d23=6160016000f3 +58cb5fb86ad9d15449738047d3b636c8da84305fc0085d159588788c8ed9cb49=6000356000523660006000f06000556001600155 cfaef2ef539e024c4a5185c0fe50c2b333446e676879766168f4b431aab1e270=7f6001600155601080600c6000396000f3006000355415600957005b602035600060005260356020536055602153600063ffffffff60006001f500 08b8b52cb0c8acbc1f7d3c022b73b922d06daf308e69a669c03e22243c29f902=7f6001600155601080600c6000396000f3006000355415600957005b602035600060005260356020536055602153600067ffffffffffffffff60006001f55060006fffffffffffffffffffffffffffffffff60006001f55060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60006001f55060006000630fffffff6001f5506000600063ffffffff6001f5506000600067ffffffffffffffff6001f550600060006fffffffffffffffffffffffffffffffff6001f550600060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001f5506000630fffffff630fffffff6001f550600063ffffffff63ffffffff6001f550600067ffffffffffffffff67ffffffffffffffff6001f55060006fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6001f55060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001f500 56e90a040e5942ed41cb57aba0bb88d80496b2b3ee5c224561348017daf29891=7f6001600155601080600c6000396000f3006000355415600957005b6020356000600052603560205360556021536000600060006001f5506000630fffffff60006001f500 215a6b4634450b670cf51948a4ac6bbcc02b064a7effdad6d09d895a704498d8=6020600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b620249f0f15060005160015500 a0bd887cab26482b2eae42e58c3b25ec2363925901e1c69ea890b43448bb929b=746d64600c6000556000526005601bf36000526001ff60005260006015600b6001f550600b600055600e6012f300 +52227e17d7647fe54dafe44b4deb62e226a5128df5abeb56b567d38dad4d665a=60003560005260003660006000f5600055 +eab3f419be128f0744b8ff553eac239abd0fa8010eb15c6e908c6906a6bf9206=7f600060005360016000f30000000000000000000000000000000000000000000060005260005b610100811015605157806001536000600a60006000f51515604657600181555b5b6001810190506026565b50600161010055 +99f533052ff998814398779b29eb17d1d9cda70c84a1c5c8de62d89afc739ba9=60003561ffff54706005600c60003960056000f3600160015560005260006000831415603257601160116020036000f090505b600183141560485781601160116020036000f590505b806002556000811115605d576001820161ffff555b8060005260206000f3505050 +aa230d92a57b6ac334b54c9a345753a57bd824c1e86bdae7d5afb69ad0b40db7=60003561ffff54706005600c60003960056000f3600160015560005260006000831415603257601160116020036000f090505b600183141560485781601160116020036000f590505b806002556000811115605d576001820161ffff555b8060005260206000f3505050 +242ffaf4896aa1a33fd22f9736aae7f38ec7926a44af5c83ecf4178c5466184b=60043560243560443560643561ffff545b838110156047576460016000f3600052600560056020036000f06000811115603b576001820161ffff555b505b61ffff5490506010565b508060005260008414156065576020600060206000856103e85a03f4505b600184141560805760206000602060006000866103e85a03f2505b6002841415609b5760206000602060006000866103e85a03f1505b60005180600155600081111560bd5760006000600060006000856103e85a03f1505b5050505050 +d21bc6ddad58c0de08949ea6b6459b6a157f5d430adc1dcc3dacfc651e30e8c2=7f60016000f30000000000000000000000000000000000000000000000000000006000526000600560006000f56000556001600155 +0cb7ff2ff5e91cde9ae944d1e97fbd4ba7846b22dd7870a48acde18e2116d79c=626001ff60005260006003601d6000f500 +fe0da0e6c1a27cd3fcd9449de9c3fc8ae987439af42de55d589e07dbe20b53a6=6b626001ff6000526003601df36000526000600c60146000f55060006000600060006000735649527a8464a86cae579719d347065f6eb27279620249f0f100 +9156fae8844f012720eec7d8aa673ad9cca3ca5dd23b928b9775b0cba8e970d0=626001ff60005260006003601d6001f500 +baab856cbce79430fa7358b1627a07ba23e047dc1feb2393baff5d6ddc6a7b9d=6b626001ff6000526003601df36000526000600c60146001f55060006000600060006000735649527a8464a86cae579719d347065f6eb27279620249f0f100 +4f730cbed6ba69e54f7096c4556fd45f9e40f12e9b3cb3ffa65ad569985cb51b=6130ff60005260006002601e6000f500 +163dc9fb46fc6db079e9223926481815c207e8d87b5b4f57a209439734a34568=6a6130ff6000526002601ef36000526000600b60156000f55060006000600060006000736cd0e5133771823da00d4cb545ec8cdab0e38203620249f0f100 +1f8670a594bb6f51563bd9bf29b0be9db17c3eda72bd1659dfd41852e3979832=6130ff60005260006002601e6001f500 +6a15f4010209e64618b949bedf2e4fd68305edffc11f62c9e2750d1fa3c9de0f=6a6130ff6000526002601ef36000526000600b60156001f55060006000600060006000736cd0e5133771823da00d4cb545ec8cdab0e38203620249f0f100 +e904075f6bb91684919a73b6f6c2faad062ac28e0d1b4b0324e37dfaed73f2bf=6b626001ff6000526003601df36000526000600c60146000f5506000600060006000735649527a8464a86cae579719d347065f6eb27279620249f0fa00 +320c0bdac224010fc389c11ded0214972cede15725f62d68bb368ebaa343fe00=6b626001ff6000526003601df36000526000600c60146001f5506000600060006000735649527a8464a86cae579719d347065f6eb27279620249f0fa00 +6adc11cbb07e63284761e20c84dd42c2f0357cf416a9765221b113cc8496b91b=6a6130ff6000526002601ef36000526000600b60156000f5506000600060006000736cd0e5133771823da00d4cb545ec8cdab0e38203620249f0fa00 +9444e91fe9e94eb25af4daa9780ce737e1a4ffdad450b59d459feb44b5cd1de9=6a6130ff6000526002601ef36000526000600b60156001f5506000600060006000736cd0e5133771823da00d4cb545ec8cdab0e38203620249f0fa00 +340145cf7877773c55440eb898245cda7ff08bffbb771df78ba3304b528ec4c1=600435803b8060006000843c60008160006000f56000811415601d57fe5b505050 +5e89e098fa8a48e4074af88f6823d5ce6305599a4ba824c41d6f249a2a45c363=60016000556001600155600060015560016000f3 +c0553b477805522c5df52fb777795c449f563514238aa02af2bff31c12129e9f=6001600055600160015560006001556113886000f3 +64f9d48dbb03e233b564cffb000d25d46d619bf7ead017c3a60da12bbda05e92=600160005560016001556000600155fe +4e8170cad07e738c37d8081a5043b7dda9218af13e3e8c2d8cc933f92056030e=600160005560006000600060006000620c0dea5af15060016000f3 +aa22e6199d06e6084cda614c3a3db0be54f5f87f362de868f596d2b68148969c=600160005560006000600060006000620c0dea5af1506113886000f3 +cc9309c1b6cb2faea24cca4c16c568792e9ba7bd09cef2a913672bd0c38382d6=600160005560006000600060006000620c0dea5af150fe +60948fb40224c78fd3a4c9aaa7e7a04973a6f7e7e78805b49dfbf819b847ea08=600160005560016001556000600060006000620c0dea5af45060016000f3 +a4eafe227ee9964f46af2519ea377ae296a117b84a91a54fde4f4a321d009830=600160005560016001556000600060006000620c0dea5af4506113886000f3 +3490e27dac61dd1c08c41a6d5fd3d6df2d5c053660def96def65826e1d059792=600160005560016001556000600060006000620c0dea5af450fe +f82e343e47b2a2164551d322270159a4d6f2e32443eee96e671d40af31792568=6001600055600160015560006000600060006000620c0dea5af25060016000f3 +6d1cf3d28163e44c11833d12ddb720f6fa12983d9989d57560375cbccc615fcc=6001600055600160015560006000600060006000620c0dea5af2506113886000f3 +93a4c5e642c58f6ea90ef828723fdacca3b8254909dc7de50b54a035add60ebd=6001600055600160015560006000600060006000620c0dea5af250fe +13febad19db39c352c37a194221a3658ab3c1d4fc7188ff7e76b4784b62ef8ca=600160005560006000600060006000620c0ded5af15060016000f3 +ca690331276298ad3f041bf742be14b44d3b308f90925e5ccc93c5a9b6c0aefd=600160005560006000600060006000620c0ded5af1506113886000f3 +bdd7b053de3ae2d9398c43459cb70dd456a242b868144cdf53c4cd94f4b1d471=600160005560006000600060006000620c0ded5af150fe +adff105dfff0c5647ec1ce6fc08d2083f927ca29e76e12f9f206a88a49724331=600160005560006000600060006000620c0de05af15060016000f3 +68f65e37716676a50230ef8fe1b50f7ae45b9a35c28f893fe6f452ee27c1c85c=600160005560006000600060006000620c0de05af1506113886000f3 +6a819c53a9ea47952ca7a953489d5625d102ea77122cf21e7376b6fb99db8872=600160005560006000600060006000620c0de05af150fe +36c8e5e4d13fb10e4f3b50768b298da7ed47dd6dc82e68b555184cd0c879345b=600160005560016001556000600155620c0de1803b8060006000843c8060006000f050600160018201f35050 +047d5aaf086bdd6f55cdcc7b5ca8f1de1f7321f7fb8f03ee6dc1b6833d9b00fa=600160005560016001556000600155620c0de1803b8060006000843c8060006000f05061138860018201f35050 +53adb60340f14943f224f428f6d3a8eb7edc14b89fb5b459eba8e1549ea187a1=600160005560016001556000600155620c0de1803b8060006000843c8060006000f050fe5050 +91bbbde20fcd7e34727b852e501b73199c4273b1b32933dfc335a18e8e8e1f8a=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f550600160018201f35050 +543016ad470d6c160504dc6c9c8ddf08b16707bde3f564c397c001a8ddeba5b6=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f55061138860018201f35050 +47916ef90b042f3a5106cff87fc7a949b0f1d40e763cfcd201ec85b4bfde6ec8=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f550fe5050 +8648b214afb7430e364eba9298aef2f4cf789dfe3c10b7169d60aca559d4db65=6000600155 +80ab328c7bf9ff6ec231b37fd3a29be9a4a52ce75a9403ac1f1d3dfa4c12e8b6=32ff +d788f00379736afa7b39a7532465cb8ea82a12dd35d61daec41b81356fda4cc2=60ff60005260206000a060fa60206000a160fb60fa60206000a260fc60fb60fa60206000a360fd60fc60fb60fa60206000a4 +23a0e63111b844c94ad18cf0e41bce1a67fa8635ec21efaf18bc6014c29f084a=6001600055600060005560016000f3 a2a11955877ae151e36f329f8bc45ab5a5565ee1d755940576841438208b830d=6d6460016001556000526005601bf36000526000600e60126000f500 7761f9e47080a9dea07ad74dcd0b4eee6bb2bc0a5d2cbe5d284f858b031765de=6d6460016001556000526005601bf36000526000600e60126000f5503d6001556000600060003e60005160025500 5dd098f4422594a7933ff26fb535c61299b4658a6cf97ac8177285a779953a47=6020600060006000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b5af2506020600060003e60005160015500 @@ -1679,34 +1470,63 @@ a2a11955877ae151e36f329f8bc45ab5a5565ee1d755940576841438208b830d=6d6460016001556 7f3f8d50c66257579347a59c8718d0fe44f047d4d2d8900090b79a05bc8940f3=6020600060006000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6180e8f15060005160015500 5c2bdcd1ae1f67776a879dd74aceb41fc56c857511707af9a1d5581fa7321744=6d6460016001556000526005601bf36000526000600e60126000f55060206000fd00 28eefca11958a6a08d7897ae3d85b49b39f1716595c9367b9fd8fc488f7b6843=6020600060006000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b5af15060005160015500 -ea87b03a322010861c9c3f2d91113817ed5af1ad5509d1d296e953d885d261f6=6000356000526000600060206000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b5af100 7e11410b197fbf51a9116b4bef381794d278bdfb0e795e859caae1f21e64f6cc=6000356000526000516002016000526104006000511460435760006000602060006104006000511473c94f5374fce5edbc8e2a8697c15331677e6ebf0b5af1506060565b6b6000600060006000f56001556020526000600c60346000f56001555b00 +ea87b03a322010861c9c3f2d91113817ed5af1ad5509d1d296e953d885d261f6=6000356000526000600060206000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b5af100 9b80084d8b54d392190ba850971ca31ab58a26470e85844e00a53d6647973a45=6000356000526000516002016000526104006000511460435760006000602060006104006000511473c94f5374fce5edbc8e2a8697c15331677e6ebf0b5af150606d565b78686000600060006000f56000526000600960176000f56001556020526000601960276000f56001555b00 3507842b88aa1c0e1f22cf1cbc3dd8f2a37e4dfd544cc4711468651f49f7110b=7d606460006000396103e85a10601b576000606460006000f5601d565b5a5b6000526000601e60026000f500 a24c75b3028d6c82ba28bd9349aa3a6c94109a221c8cf79637c1873255454624=69600c600055600d6001556000526000600a60166000f500 9906997c04cc7ac0c88e7e25b9cf3b0b36b808b8090b395adb1fb1ea00d94870=60016000556000600060006000600073b000000000000000000000000000000000000000600035f1600155600c60045500 88ab1b584b23704782ea1a04695ae304adf2f3826b4297db965d2568d2a1e1d8=60086002556000600060006000f550600c60035500 +b9134334f82ce111680bb32468b9df3d41061303d1511e4b9361eb7d22dbbd74=30506000600e80602860003960006000f56002553d6000556020600060003e6000516001550000fe6211223360005260206000fd0000 01775ea3ee583a2e77f1f14633400a5385e341e5ae3ac38eec026cd58fcb252e=6e600160005560016000fd60116001556000526000600f60116001f5600155600c60005500 3d57290be527913c1e95ad5333a6100955c93d8856983312dc60e9e56ab52715=6000600e80601760003960006000f5503d6000550000fe6211223360005260206000fd0000 b37864a984e35fc2d0e7ceb61198503de2988d27a5510464f54dbaba442ffd48=7d111122223333444455556666777788889999aaaabbbbccccddddeeeeffff60005260206000f300 73d60d979b543a41feef88f3749f87baac94113d0540f97fe77a301649960067=60206000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f1506000600e80603e60003960006000f5503d6000550000fe6211223360005260206000f30000 -8a168d3c2b531bbfb7eed870f0c15ff2d5229fe26db10fe47625a97cbcb51e88=60006000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f1506000600e80603e60003960006000f5503d6000550000fe6211223360005260206000f30000 6c6d1b053e052e2aaaa460b4c0db743515eb307279b458b6a2ef9b18c846db38=7d111122223333444455556666777788889999aaaabbbbccccddddeeeeffff60005260206000f30000 -8d71f1baf932ccfe51802cd53663486a5e45cb95151cb1a322ec39a141518cd3=600060006000600060006000355af100 +8a168d3c2b531bbfb7eed870f0c15ff2d5229fe26db10fe47625a97cbcb51e88=60006000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f1506000600e80603e60003960006000f5503d6000550000fe6211223360005260206000f30000 +c79e0198cf5bd2391dfab79ab4a5f727191b360097e4480f46ba6b55343c6fd1=60006000536000600160006000f560005500 +a1c0af891959756f7603db930bde8c199d25c3b45e93892f65e2fc58a6e84d01=60566000536000600160006000f560005500 +170d0e39252912ff91a1ecaca213518f87e5ab208f0b1de87b643d79b6e5a7dc=60016000536000600160006000f560005500 +5fbdc0a1ec766446c7bb63bf261e8d9c551ba3bee3b01ad04ec855610a90c555=60f46000536000600160006000f560005500 +76a20ad723a19ff6ee0f1fb94b0e4266f5a2c7bf3fb869320dab8c233fb8d7b1=6a60016001556001546002556000526000600b60156000f560005500 +af92af26df14fab9cfeacf2d1ea273af589f14a70a6a9f85c81fb3b8a1a9634e=626001ff60005260006003601d6000f560005500 +1f224ef3dee7bce1e818896ba56cea12fa5929f5322ff3cc30935666a995a355=626001ff60005260006003601d6001f560005500 +343399ee1d228e1f9967c71d5018fcb3a10487d7158a3686918df63869426864=60006003601d6000f560005500 +4dea22089412be26f403665dec5b440f064752f4e3f1580981b6f743f6914f10=6160a960005260006002601e6001f560005500 ca6d627872c35c5437a29a3fabda1f3f19b675a53ff0c281339bb7c0c8d6409c=7a600060015414601157600a6000f3601a565b60016001556001ff5b6000526000601b60056001f56001556000601b60056001f560025500 +8d71f1baf932ccfe51802cd53663486a5e45cb95151cb1a322ec39a141518cd3=600060006000600060006000355af100 20aed0d47cdf2f12c13f245182de6e26d4c3e26ebc16b02e6e09da2268d389e3=7c600060015414601157600a6000f3601c565b6001600155600a6000f35b6000526000601d60036001f56001556000601b60056001f560025500 +0ceab5d26ca0b097ec0e2b5a810d9a46a576747f5a2ee39acf1125dbefa1e379=6000602980601160003960006000f500fe61010060006000600073f2000000000000000000000000000000000000005afa50600051600a550000 +02aa5a85c50eccbdd3714fe0c173fe47a7ec78e3b98e0166542c0d3d55dc1bf2=6000602480601360003960006000f5500000fe6000600060006000600073f0000000000000000000000000000000000000005af2500000 +556f9c674339d5fd4c44ca3c79b25d43b95ba0dfc0753b4e551406a92576edb9=6000602280601360003960006000f5500000fe600060006000600073f0000000000000000000000000000000000000005af4500000 a27ff87311b40a91645d0e29e85f17bef428ee98334082d8810a81ebc72bfe80=6000602380601360003960006000f5500000fe30600055303160015532600255336003553460045536600555386006553a6007550000 +c3fa0ace59c7d664250610583f9f21f2688f488bd99e107964cf0b1d69977d17=600060006000600073f0000000000000000000000000000000000000005af4500000 +fb57d4384857666596aa0f1ae985061514c50d24c6536985e93c7721f26ab366=6000600060006000600073f0000000000000000000000000000000000000005af200 +f2cba7b387262c5d65c0c23f4c7920ed5cb1ce9a55eb6959781cf1f39775f143=6000602980601160003960006000f500fe3060005230316020523260405233606052346080523660a0523860c0523a60e0526101006000f30000 a36567eb706d26cb1f601f73396df65f77eec2935c59d347a1f1525b4e7e5dbc=61010060006000600073f2000000000000000000000000000000000000005afa50600051600a5500 -556f9c674339d5fd4c44ca3c79b25d43b95ba0dfc0753b4e551406a92576edb9=6000602280601360003960006000f5500000fe600060006000600073f0000000000000000000000000000000000000005af4500000 -02aa5a85c50eccbdd3714fe0c173fe47a7ec78e3b98e0166542c0d3d55dc1bf2=6000602480601360003960006000f5500000fe6000600060006000600073f0000000000000000000000000000000000000005af2500000 -0ceab5d26ca0b097ec0e2b5a810d9a46a576747f5a2ee39acf1125dbefa1e379=6000602980601160003960006000f500fe61010060006000600073f2000000000000000000000000000000000000005afa50600051600a550000 -f2cba7b387262c5d65c0c23f4c7920ed5cb1ce9a55eb6959781cf1f39775f143=6000602980601160003960006000f500fe3060005230316020523260405233606052346080523660a0523860c0523a60e0526101006000f30000 c3ce08944bad51dc73b907a561f88e768067ad7797c597f4e57126175c6be569=6000602480601360003960006000f5500000fe6000600060006000600073f0000000000000000000000000000000000000005af1500000 7b3b54ebb35862901dec1f208e1a51ae747dabaf9434b1c8a5272baa7eaa7207=6000600060006000600073f0000000000000000000000000000000000000005af100 -fb57d4384857666596aa0f1ae985061514c50d24c6536985e93c7721f26ab366=6000600060006000600073f0000000000000000000000000000000000000005af200 -c3fa0ace59c7d664250610583f9f21f2688f488bd99e107964cf0b1d69977d17=600060006000600073f0000000000000000000000000000000000000005af4500000 +fd39994f2b05bfbff9216d2e0ff446e83c2504d25ac18ca1c69efbf13d5ce691=6000600060006000f500 +8709980edfa2db2bca11f56a4f8ccf4f40130495b192afc3d66338be29c79fe8=64600160015560005260006005601b6000f500 +edc3d79069c655807240f56f6d25b23bc70fb7f74b6c3c72ceb022842193cf96=6000600060006001f500 +97701eaa65e57bfd257e872adbadb1564174326e325d358f9074c94c3982d68d=6b620102036000526003601df36000526000600c60146000f500 +81857195aa42f0d424d0f68d3d53dbbbc556c4baf6ffb3c5f3434996a3080652=6b620102036000526003601df36000526000600c60146001f500 f67c16edb59aa3dff868b05a58639d544bf606f34f158e966bc8b6fb2767f485=6010ff00 +a33f1f7f11cd1cf39ca6dd8efa5bf35dcccf71aa76f5b483936b4c9b1303ece5=6000600060006000600073fce41d047b4a1d4450382dcc29ec7e5fedc5f9a361c350f1506b620102036000526003601df36000526000600c60146000f500 +08526b9d35d551a58be04ac9d2112ea7b61296f9997ed1b813f90eda1d170f7f=6000600060006000600073cff64f4c5df8f436c4f2c1af4b2e3f9e3004c77961c350f1506b626010ff6000526003601df36000526000600c60146000f500 +a5ba2215589e9001f8e09e6d4b20d10984ccf41127a7c1541412d8a143cc9ed5=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c61c350f1506000600060006000f500 +b67531ccc44e5125b256f0a2ddbc2dd196a581ec2ecc6036111856343cb11b23=6000600060006000600073af3ecba2fe09a4f6c19f16a9d119e44e08c2da0161c350f15064600160015560005260006005601b6000f500 +751304facb1eaaf42eac0410f7c198c2bccec0ef5f539437540b863e2227c34c=6000600060006000600073ec2c6832d00680ece8ff9254f81fdab0a5a2ac5061c350f1506d6460016001556000526005601bf36000526000600e60126000f500 +8098eeb5bc9d57bdc6a129d382eceb3ae0cddbf1b097becd1525a3ef74dd8720=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c61c350f1506000600060006000f5506211223360005500 +3079d3cb0f0da4e5498df92c5d46dea0149cf57011aa0a6b734b2ca5c8829660=6000600060006000600073af3ecba2fe09a4f6c19f16a9d119e44e08c2da0161c350f15064600160015560005260006005601b6000f5506211223360005500 +3713ee134881ec75e4d2dddc2e794f0d413f667ea2f7318b2b356fe7487f7802=6000600060006000600073ec2c6832d00680ece8ff9254f81fdab0a5a2ac5061c350f1506d6460016001556000526005601bf36000526000600e60126000f5506211223360005500 +b241e18beb9a689473427ca122ae13c4923908e5f245ceae722019fd848d1b15=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c61c350f1506000600060006000f550621122336000526003601dfd00 +05711be14dd842613c5207685cb7989b9e037d5560062bf20b630ed3c0ac5e34=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c61c350f15064600160015560005260006005601b6000f550621122336000526003601dfd00 +e24df00f2cc0d6b3c1fad7bbe374fdca414384c13d4aa0a379ae6015ec40c656=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c61c350f1506d6460016001556000526005601bf36000526000600e60126000f550621122336000526003601dfd00 cbcbacf78ef46e786e2fa02c3e8d0f1c5cbd25b5e056f05d9d5e08ddda5d4291=6000600060006065f500 +f3802b7c46d0e643142b13742279ae9721de44f8617aafbd5b0a68f8ea8731d5=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c620249f0f100 +5522f10e8623be56f3fcc3a05e5dbd29520a6bf3092eb495d60553cfa1973e9e=6000600060006000600173e2b35478fdd26477cc576dd906e6277761246a3c620249f0f100 +a1f611faeec2bab60b99b53874198369701ba7d12bf2b948d2711c73d6b4679a=600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c620249f0fa00 ffee2a3059880493356b38e75e9916952f95f87ee6d8d4df78a1eac3eef77ead=6000600780601f60003960006000f5506000600060003e60006000550000fe60016000550000 d1db4113edcc36703edd7bfd3cdc7ef94ce8de79e914d561adacdf35f9435bd4=69600260005260206000fd6000526000600a60166000f5503d6000556020600060003e60005160015500 9c42984af83861dbc3420b806db74cfcb85e140a5e7f7e566b307480d9655d0b=6000602880601f60003960006000f5506020600060003e60005160005500fe7d111122223333444455556666777788889999aaaabbbbccccddddeeeeffff60005260206000f300 @@ -1716,6 +1536,7 @@ fbb431f2189ebaffc4f9c1b0a170a321958396ed8b683e1ba534787f4064beba=600060298060206 3694d6a2e270143e1b7ad42de73c57175a13c50dfd52d1be17f5b34ba872fd34=6000600d80601760003960006000f5503d6000550000fe6211223360005260206000f300 4cc61e1ed6d2e4e5227c4388744a5b9cdacad746f9620ddb6ce11a9aabd8c23b=600c60015500 63d1873266f31c5c1211c5e798508c6222574120b233cfc18cf34ca6ac238bfc=5a600055602060006000f06001555a6002556000600060006000600073e1ecf98489fa9ed60a664fc4998db699cfa39d4061ea60f16003555a60645500 +50ac9394e4391fc0702cfc7b594d452128fbda9f4060d0f949916d03701fcc4d=6000356000523660006000f0600055 6e7614d58424c8409591332959588c34ee21514f7a8ea69e76a59e4c994c50cc=5a600055602060006000f06001555a6002556000600060006000600060015461ea60f16003555a60645500 c014473615e7e31367489957d58724908eeb02d7bc2200959781a5bbfaa5381e=5a600055602060006000f06001555a6002556000600060006000600160015461ea60f16003555a60645500 bc1e9da083d9ee4773f2e596ffe3d2f8d56fc65822fb05e489dab7f3d9e1d9f0=5a600055602060006000f06001555a60645500 @@ -1723,22 +1544,69 @@ bc1e9da083d9ee4773f2e596ffe3d2f8d56fc65822fb05e489dab7f3d9e1d9f0=5a6000556020600 588b8618ca23c9938da936cad23b8a754426f9101d2cd743bb76d08fb6d54491=5a6000557f600c6000556000600060006000600073c94f5374fce5edbc8e2a8697c15331676000527f7e6ebf0b61ea60f1000000000000000000000000000000000000000000000000602052604060006000f06001555a6002556000600060006000600060015461ea60f16003555a60645500 9f443d4664f4165129254b21d2aa9f402e990ec3f21c8a3557c9053f13a8bb47=5a6000557f600c6000556000600060006000600073c94f5374fce5edbc8e2a8697c15331676000527f7e6ebf0b61ea60f1000000000000000000000000000000000000000000000000602052604060006000f06001555a6002556000600060006000600160015461ea60f16003555a60645500 4fef7f1b0a5d0be8d7231aba1a5e3ea4d34f7dc7dd96071b4c04e6e43716bd91=5a6000557f600c6000556000600060006000600073c94f5374fce5edbc8e2a8697c15331676000527f7e6ebf0b61ea60f1000000000000000000000000000000000000000000000000602052604060006000f06001555a60645500 -3b0b68a7a28df4b5781690a493c35a0625901aa7b3dcb525b1949e33e7bdc4b4=6000600060006000600060003562013880f100 +0e64b07c5f8a4b1d805d72a663b7922bebd1fffc63fdda9f74ee833a962cd08f=7f600060005360016000f30000000000000000000000000000000000000000000060005260005b610100811015604f5780600153600a60006000f01515604457600181555b5b6001810190506026565b50600161010055 +0f80ade5cd0aebbf46caac3e6642ca49675bc577b59305821c4f28ff215d106e=7f60016000f3000000000000000000000000000000000000000000000000000000600052600560006000f06000556001600155 +8f2b325bc960e0b2589c62f03544cb60df9ff0743d658cd3b2531de5b60d4036=6000356000545560016000540160005500 +2ab24936454b2c8365281adf6aa1abbeab4c3834a3470510287a934d1f9fd054=60068061004c610100396102005260db8061005260003961022052600160043514603757615a17610200516101000160006000f56045565b610200516101000160006000f05b6102405200fe60ff60005500610100610100610100395861026052600060006020610260600061da7a62fffffff1503061026052600060006020610260600061da7a62fffffff1503861026052600060006020610260600061da7a62fffffff150303b61026052600060006020610260600061da7a62fffffff15060206000610100396101005161026052600060006020610260600061da7a62fffffff15060206000610100303c6101005161026052600060006020610260600061da7a62fffffff1505861026052600060006020610260600061da7a62fffffff1506101003803610100f300 +8fe0d0b35be498ea58c02e2f3bfd06f7ff8c08eb81f04115affacd68520f5ee1=601d60005500 +6bc0f214f1d46352212bff0bb2bf8f22e56a258863ee84aab805ba06e3044fde=60f860020a6000350461010052601580610158610300396105405260068061016d61020039610520526001610100511461004957615a17610540516103006000f561060052610058565b610540516103006000f0610600525b586020553d6010556106005160115560006000600060006000738af6a7af30d840ba137e8f3f34d54cfb8beba6e261fffff16106405258602155600161064051036012553d601355600060006000600060007340f1299359ea754ac29eb2662a1900752bf8275f61fffff16106405258602255600161064051036014553d601555738af6a7af30d840ba137e8f3f34d54cfb8beba6e23b6030556030546000610660738af6a7af30d840ba137e8f3f34d54cfb8beba6e23c610660516031557340f1299359ea754ac29eb2662a1900752bf8275f3b60325560325460006106607340f1299359ea754ac29eb2662a1900752bf8275f3c6106605160335500fe600680600f61020039610200f300fe60ff6000550060ff60005500 6ec4750d6b26b36a640db94d86ffea865b5e7c2c4ec374fe9bfcabc0ba2847b5=6460016001556000526005601b6000f060015500 +3b0b68a7a28df4b5781690a493c35a0625901aa7b3dcb525b1949e33e7bdc4b4=6000600060006000600060003562013880f100 +faa74b0b8c25e339bcbc2891614c363020f5bcabc51694e5519efe90cc6184d3=600435803b8060006000843c8060006000f06000811415601b57fe5b505050 +a27d87251798a593b75d6fc3305ed0eba86be2c4281283e6ec41a596d6ea23ed=60016000556001600155600060015560016000f3 +cc0f8546303c24ff600f1084b88781cc91f432173256a6e0fec568f530130ca6=6001600055600160015560006001556113886000f3 +af7b42087df475463f3f4681f43871f54737ecb874aeccc22c513978312d5c7a=600160005560016001556000600155fe +a80a8bffdd8dfcedecf9fec790b91200681b9680e658f239cf2f43ce41872497=600160005560006000600060006000620c0dea5af15060016000f3 +1b3e88ede6b23b56ae8e682a5f59f5b7952cd6d0a4021feb90ba28d9c33881bf=600160005560006000600060006000620c0dea5af1506113886000f3 +5e64f31cc3d60a722b54b1dd990213d114b43afb91bbdf1fbd253a0b0e09da2e=600160005560006000600060006000620c0dea5af150fe +9756ccce0af3ab7f2ddcd9ead3417771c3e13e76f1982ef66757f2b9773908a7=600160005560016001556000600060006000620c0dea5af45060016000f3 +9859a54aafd2db530ca791b7cc9f75dc42a4750f17a2572175e5ff253401dc5c=600160005560016001556000600060006000620c0dea5af4506113886000f3 +6cf00b462393771a4d13d9a6a81721d3f576cfcf6d980a7ac0bf5ce9feb3c90e=600160005560016001556000600060006000620c0dea5af450fe +4f1407a0d00cfdd4938f41333df0db261155dcb8957dbf6e8a5aea79b4c39d64=6001600055600160015560006000600060006000620c0dea5af25060016000f3 +de71dee39e096d303abbe8e0d9b854de76c7abba0f5c868b618ea8f18e7adaa9=6001600055600160015560006000600060006000620c0dea5af2506113886000f3 +6b70aedf8a9e0995baf0ca14afadf1f1b2b8ff97b07ddc35c1654a17b3321c51=6001600055600160015560006000600060006000620c0dea5af250fe +53964f63ba7984d3ea9f17e77bf61770d262605e1b9afc6b5dc3b08ce76c9e07=600160005560006000600060006000620c0ded5af15060016000f3 +2823105003d7f7bcb6a57448f36820843bdba58e19b23e548b99f0804b93fdb2=600160005560006000600060006000620c0ded5af1506113886000f3 +16a843c37a1f02710eb64f1b0a8c09151cf80cc38bebae862f782b7d5c16c92f=600160005560006000600060006000620c0ded5af150fe +62e06c8f58c452573ea2dedf8f1775060d6ceca56f811765344a61868cb5c5b6=600160005560006000600060006000620c0de05af15060016000f3 +a30a1c1183bf98b15857ad1054e59dd365ecad93d3a22ec182750e2879cc0ad3=600160005560006000600060006000620c0de05af1506113886000f3 +d5995b05f6a20e0100d0cfd60f01e0ad1094b297fa5311107fca3c5e96108b2e=600160005560006000600060006000620c0de05af150fe +8cfc1ffde61af5b3a4c41ca48021e77291241e208e853eab1d5dce96c392b1d6=600160005560016001556000600155620c0de1803b8060006000843c8060006000f050600160018201f35050 +0793730d42a2860ea9ee769705c5870d6cda60dfb4d781105c7f45db491026ea=600160005560016001556000600155620c0de1803b8060006000843c8060006000f05061138860018201f35050 +9fc54038403be74936d2bf3282e4986caa6e7867abf72b992b78dac6b9ed7555=600160005560016001556000600155620c0de1803b8060006000843c8060006000f050fe5050 +fa33b07cd047c51c449ba132a5bff6ba06f377530b02d88e2befe8a6663b67c4=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f550600160018201f35050 +44fcf2437a6eb80065abd34775b314990164b8cbd17c325aeac7932035089682=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f55061138860018201f35050 +b253d47579a0e1c65178b50c589e110c1efe4d2b82771cdfb1b85820bc56d951=600160005560016001556000600155620c0de1803b8060006000843c60008160006000f550fe5050 72a954af5006562f0dfb34e46464fdcd1a793f13b7356b2b6917ce16ae9fe447=6d6460016001556000526005601bf3600052600e60126000f000 8d3966a550258f89fd720a3a7b1a679fdd35354a926a6b798f38074a44c1352b=6d6460016001556000526005601bf3600052600e60126000f0503d6001556000600060003e60005160025500 cace50ebb0fb04dc5d78ecaf4ed9bdad4c5ba918c13b44605d82630d472cfaf5=6d6460016001556000526005601bf3600052600e60126000f0503d6001556020600060003e60005160025500 202db2b317af70e9ac3cda5a8d314345fe4b2188daea61087e9908fe7d45bcaa=726960016001556001600255600052600a6016f36000526013600d6000f0503d60020a00 -c66ba2e979c0d75239d1097adb2387c7918cf6ba151ad35697e0e17ad05f674b=6d6460016001556000526005601bf3600052600e60126000f05060206000fd00 4f8c74954df3634bebd2fc766b4288f4ddbf31a4780966679927bbbc5c211772=6020600060006000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6159d8f15060005160015500 +c66ba2e979c0d75239d1097adb2387c7918cf6ba151ad35697e0e17ad05f674b=6d6460016001556000526005601bf3600052600e60126000f05060206000fd00 f7294423dfa4154ea5a6b3ac3cc4d02bb309bef32739d78422b4ac88dc4d838e=622fffff60002000 1a282d2e56e29c13ec3fb7abb753de1f5d5b0d384059764043de57d1bb1bf213=6d6460016001556000526005601bf3600052600e60126000f0506000600060006000600073094f5374fce5edbc8e2a8697c15331677e6ebf0b612710f25060206000fd00 +996cb8a428e971c6f11083e3145eec7d57824c1e0a3c7ab0b2c813797bf6dc85=386000556000361115600f576000ff5b +0ab50e48e5899bad047f2e35a53e0bdfa7f586424a34e03c540244e910bf42c4=620c0de0803b60006000833c6160006000f350 +368981308235cb257758010274fb07e7d9f8eed95cc019c6533d9cb6e944b77b=6001600155600035602035620c0de1803b8060006000843c60005b84811015603b578160006000f08060208302840152505b600181019050601a565b506000831115604657fe5b6020840281f350505050 +f56e738504b614f030b881a1aa1ab1fe0f8bf17565fd539ce0b000df49765dbc=600435602435604435606435836000526000602052604060208502808260406000620c0deb60025a04f4600081141560375760006000fd5b85600052846020526020870260400192506020860291508183604060006000620c0deb60025a04f190506000811415607857600085141560775760006000fd5b5b86600086141560875786880190505b60005b8181101560b757602081026040015160006000600060006000856103e85a03f150505b600181019050608a565b5060005b8581101560e857602081026040015160006000600160006000856103e85a03f150505b60018101905060bb565b505050505050505050 +b6c5a45d051cd5bc14c41fa06350d5c433107570d31b02b189232f4d40f29831=60043561010052602435610120526044356101405260046101405114600061014051141761002f5760005061003e565b60218061025061030039610540525b6001610140511461005157600050610060565b60298061027161030039610540525b6002610140511461007357600050610082565b60268061029a61030039610540525b60036101405114610095576000506100a4565b602c806102c061030039610540525b600561014051146100b7576000506100c6565b6028806102ec61030039610540525b600661014051146100d9576000506100e8565b602a8061031461030039610540525b60128061033e61020039610520526001610100511461011757615a17610540516103006000f561060052610126565b610540516103006000f0610600525b586020553d601055600461014051143d1761014357600050610153565b602060006101603e610160516011555b610600513b61056052610560516000610400610600513c61056051610520510360125561040051610200510360135560016101205114610195576000506101ac565b600060006000600060006106005161fffff1610640525b600261012051146101bf576000506101d6565b600060006000600060006106005161fffff2610640525b600361012051146101e9576000506101fe565b60006000600060006106005161fffff4610640525b6004610120511461021157600050610226565b60006000600060006106005161fffffa610640525b58602155600061012051141561023e5760005061024d565b600161064051036014553d6015555b00fe601280600f61020039610200f300fe600060006000600060006160a761fffff100622fffff60002050601280601761020039610200f300fe600060006000600060006160a761fffff10060006000fd601280601461020039610200f300fe600060006000600060006160a761fffff1006160a760005260206000fd601280601a61020039610200f300fe600060006000600060006160a761fffff1006160a760005200601280601661020039610200f300fe600060006000600060006160a761fffff1006160a76000526000ff601280601861020039610200f300fe600060006000600060006160a761fffff100600060006000600060006160a761fffff100 +e6c9a9cd0576a0827c6d7e153bad1773be79b062b739d821e314d228becc90d3=6160a760005500 +1269e1165214001763734f4ab9e8b4af94c6784128543571388100b0a8c2dd53=63deadbeef6000526160a760205260406000f3 +7b5d67ae9317ae71fd4c0d26534e80a90ecc51e6970da1b80ff0de5896ae993a=650bad0bad0bad60005260206000fd +cd4d3c09da11087ab7bf7869059e607ed149955ae16144b9b704b83d17b6552f=61600d60005260206000f3 +936fa4ee803af69ccca98fa58ec947c8200668c125be49d4673bd30b100c9f39=604061010060006000600061da7a5af16010553d6011556101005160125561012051601355600035803b8060006000843c8060006000f06000553d6001553d60006102003e61020051600255610220516003555050 +5365da138b0f9466cea68b6eecf601e402750cb8e13782201eaa011bd716f3d5=604061010060006000600061da7a5af16010553d6011556101005160125561012051601355600035803b8060006000843c615a178160006000f56000553d6001553d60006102003e61020051600255610220516003555050 +2919a2ea3a06a002625142a11b44d8ee0180ba391c0273c49ee6e66b584127ce=604061010060006000600061da7a5af16010553d6011556101005160125561012051601355600035803b8060006000843c63bad05a178160006000f56000553d6001553d60006102003e61020051600255610220516003555050 +16977ca088151212b46237b6c336d138f8bfd24129a63424ce9aec7eab7d47ad=604061010060006000600061da7a5af16010553d6011556101005160125561012051601355600035803b8060006000843c8060006000f06000553d6001553d60006102003e61020051600255610220516003555050 +7945813967cb96252b4d804e32df042ffd0df0cdbde6294bbdf40b02ed0f0262=6004356024358162c0de0001604061010060006000600061da7a5af16010553d60115561010051601255610120516013555a60068314156046576004615654026175300190505b8260005260206102006020600060008686f1806000553d600155610200516002555050505050 +0f40edb53bcfa6f1d0b2756709e14a6609b10de043a398af6291a6beda197a48=600019600052602061010061010039610100516000f3 +614f9f94e270fc2022d8845ecd77cc8daabca21b4b140b8f9f7c4c61753cae23=60043560243560443561c0de3b806000600061c0de3c826001820353816101005260008460f0811460355760f581146043576051565b61012060006000f091506051565b615a1761012060006000f591505b50806000555a600155803f6002555050505050 5a7d04b359943ed94efac3837ef063438beffff6facc990229c19b49b7348e1b=600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff460015500 ae55b10532d3bf62548b4bff144544b45ee68ff8efeb6ef266609904dbe7a9b3=600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b610401600054046001036127105a0302f46001556103e86000540260010160025500 b424a9fc173523f0ddaf08491e9a131e4cf6320fa57fd3687e17db02d8391a36=6000600060006000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffff16002556000600060006000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffff1600355600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff460015500 512a7e819ae177c42e94558e8dbfdd801a2dc4706b3148d3b5b9350071a4f85e=600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b620186a060005402600101f46001556103e86000540260010160025500 -fdba06429bd93561b41c5953611bb7ffe0b3b706509a872d20c09606d4a051e2=6000600060006000601773bad304eb96065b2a98b57a48a06ae28d285a71b5620186a0f150600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b56707fffffffffffffff400 6403d40db5100426f4be765613d8db9d58f6b1b276a0d0cffeeff1264b787e8a=6001600054016000556000600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b562036b005a03f160015500 +fdba06429bd93561b41c5953611bb7ffe0b3b706509a872d20c09606d4a051e2=6000600060006000601773bad304eb96065b2a98b57a48a06ae28d285a71b5620186a0f150600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b56707fffffffffffffff400 451d06e323434c52e2a3d65400abaac0b245634eb0f33307723c2e276ac83b32=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350f45060005160005500 a0fe427a36ac004b74ca059fffb2c45e481bd46f564281299e03c66b64dc3a26=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600060006020600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350f45060005160005500 c65245e65a9bed57921028dcb30c7a2e52fde9f6c793fcb24b969f87b997ccda=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052602060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350f45060005160005500 @@ -1761,23 +1629,23 @@ ebaea091530c8b5e967c7f905a7014dc4a371a5137e95f6a59d3d211efeb80d2=3360015500 da3cfc7add3b6e8a0021988a4fc18e6e9a9777111550dbeb9b8b55c07eaa7001=7f716860016000553360145560005260096017f36000526012600e6001f0600a556000527f604060006040600073ffe4ebd2a68c02d9dcb0a17283d13346beb2d8b66201866020527fa0f4600b55000000000000000000000000000000000000000000000000000000604052606060006001f000 ffcb314bb59677ab6c9d61dbdc62cf0048c65ce6f887e99d155542035f3672ef=5a60085560006000600060006000731000000000000000000000000000000000000103620927c0f160095560006000600060006000731000000000000000000000000000000000000103620927c0f2600a5500 49573c7b64cf37a3b4500965d34edd61658abf517c5349443dd1b4b207fa8633=601260005500 -68322fd65ffc3848db62898f9a624413c70af4f57322bcfbdb900551fd2f9176=5a60085560006000600060006000731000000000000000000000000000000000000108620927c0f160095500 -016d949e2d94b04a422ce01d9b6b8814ac56de8730447894c127d6b34a942b42=5a60085500 1f2652b1c89a3813b6f38ba3dbef143dc331428de3b5ddcf96877c64b391256f=5a6008556000600060006000600073100000000000000000000000000000000000010762030d40f160095500 +016d949e2d94b04a422ce01d9b6b8814ac56de8730447894c127d6b34a942b42=5a60085500 +68322fd65ffc3848db62898f9a624413c70af4f57322bcfbdb900551fd2f9176=5a60085560006000600060006000731000000000000000000000000000000000000108620927c0f160095500 +e24d0510cfdb27d02652a2093bb0ab7c072a142e875da65ec872c8db043ea87a=5a60085560006000600060006000731000000000000000000000000000000000000114620927c0f160095500 5a12bedda1432446b7eec7329b1b305da2685f9444140a847891658049fa929e=5a600855622fffff60002000 cb7f48a28e3b7344d383cd49b2657a0c20bc109c28dd890ec0b313afa643460e=5a60085560006000600060006000731000000000000000000000000000000000000113620927c0f160095500 -e24d0510cfdb27d02652a2093bb0ab7c072a142e875da65ec872c8db043ea87a=5a60085560006000600060006000731000000000000000000000000000000000000114620927c0f160095500 +e5ea9813b1a45461a2c6b4b4d54e1b2bc84c43492a60e67790431bc764241205=5a60085560006000600060006000731000000000000000000000000000000000000110620927c0f160095500 4a7fd2dbe174b72f892e2a64d82d493c802bb9cb7cd0f499a37bc32903b6e205=5a600855622fffff600020505a6009555a600a5500 7cc4db19afdf9c3ccd33c8f4b8003c832abbaec2de7923147b7b316652b8595f=5a60085560006000600060006000731000000000000000000000000000000000000111620493e0f16009556001600c5500 -e5ea9813b1a45461a2c6b4b4d54e1b2bc84c43492a60e67790431bc764241205=5a60085560006000600060006000731000000000000000000000000000000000000110620927c0f160095500 2fb5ca46ea750c14fff562ff06e6e2ce55b347d6f2bad23cd79f48f076d86148=5a606452635a60fd556000526004601c6000f0600b555a6064510360095500 078aa7a67e05378d2d6a01c7849209aa1e715ff722779ad7236ec0f607cb837d=5a6008526000600060006000731000000000000000000000000000000000000105620927c0f46009555a6008510360085500 -e952288bfd7d359e8e6d68c34e8f374ecb9bbc6d3b31bdaceae8a92b6dcda854=60006000600060006000731000000000000000000000000000000000000001620927c0f160015500 15ba436321000c9c5343067ee4a6ae690f10cbdf8bd2839ccb53920beb05667a=600c60015500 +e952288bfd7d359e8e6d68c34e8f374ecb9bbc6d3b31bdaceae8a92b6dcda854=60006000600060006000731000000000000000000000000000000000000001620927c0f160015500 eb8e9149bbe1ef10c9bb97aefb652f40040aa4b8b99e6d2bebc607cabc4a6071=601160645500 4a20311675b86136b91882212546df94ac5adc617567ceb81b905635606f0c80=5a6103e7527310000000000000000000000000000000000000103b6001556014600060007310000000000000000000000000000000000000103c60005160025560005460045560006000600060006001731000000000000000000000000000000000000011617530f160055560006000600060006001731000000000000000000000000000000000000011617530f26006556000600060006000731000000000000000000000000000000000000011617530f460075560006000600060006000731000000000000000000000000000000000000013617530f160085573a94f5374fce5edbc8e2a8697c15331677e6ebf0b316003555a6103e75103600a5500 -d50f384149292a2da6a35604e0c706c197c311494ef9767a50d597f341a7171a=5a6000526000600060006000600073100000000000000000000000000000000000011861ea60f1505a6000510360015500 774633243e64cf3ebc40608cd4a5d4e63aa60c5de4c19caaccb7eea0b2ec60f6=73b94f5374fce5edbc8e2a8697c15331677e6ebf0bff00 +d50f384149292a2da6a35604e0c706c197c311494ef9767a50d597f341a7171a=5a6000526000600060006000600073100000000000000000000000000000000000011861ea60f1505a6000510360015500 6e131966e19f64076f1fb97dc8dfe75255336e26958c64ee9974266d60390329=5a6000526000600060006000600073100000000000000000000000000000000000011661ea60f1505a6000510360015500 fa34d1e0544d9f4d11d1839bded8f96c4357b060adab2f42dce8965629ff5198=732000000000000000000000000000000000000115ff00 9c6be42daef8d1f2b41ab7e221cbaafb0e2af8d9b7d5bd9c81f98c42e505c386=5a6000526000600060006000600073100000000000000000000000000000000000011862027100f1505a6000510360025500 @@ -1812,21 +1680,64 @@ bf10975cc440aded84d6eac3c092abc0002459eff431ba3eec00730eab7b7d7a=5a6000526000600 d4fa34333626391fa16ba871356867b8fd206caca8d85e148a2972428c77527a=5a60005260146000602073094f5374fce5edbc8e2a8697c15331677e6ebf0b3c5a6000510360015500 dfaf57e11e1718b00f56af3da8fe4df4855a9eda9805d4f61b8a15484bb0f7c6=5a600052612b706000602073094f5374fce5edbc8e2a8697c15331677e6ebf0b3c5a6000510360015500 1824c3148c7e54778f96afa858a88bd5a120f6827260b55ddb2470b6f9ba1110=5a60005273094f5374fce5edbc8e2a8697c15331677e6ebf0b3b505a6000510360015500 +bcb81a6c528c12438c87aadc3c9279ce698f793a68545acda702481c077fb8a3=61de57ff00 +0bcd73d8e5f61bb45310fabfd6225ec7167e25dabcca2092088ffa146da82697=60ff6101005260ff6101205261ca113150603160043514610021576000610026565b61de57315b50603b6004351461003857600061003d565b61de573b5b50603c600435146100505760005061005b565b60016000600061de573c5b603f6004351461006c576000610071565b61de573f5b5060f160043514610083576000610096565b6000600060006000600061de5762010000f15b5060f2600435146100a85760006100bb565b6000600060006000600061de5762010000f25b5060f4600435146100cd5760006100de565b600060006000600061de5762010000f45b5060fa600435146100f0576000610101565b600060006000600061de5762010000fa5b505a610100526000600060006000600061ca116301000000f1505a610120526008610120516101005103036000555a6101005261de5731505a6101205260086101205161010051030360015500 +d42e9f38b89050995a8a617e6c0fdd3248ed70f24ce86aee37b162c2d20f677b=61ca113100 +273497c224638b670119ffe1daaecf48f6b31d6cf19c9ec01bb26077c04a097d=6101005400 +739be5ba6ccf4f8fc16d0a08bf7747476b82bfea98095649c65ba27bc02bc509=5a6000525a60205264ca1100ca11315063ca11010031506004356040525a600052600160405114610031576000610036565b610100545b5060026040511461004957600050610050565b6005610100555b600b60405114610061576000610066565b61ca11315b50600c6040511461007857600061007d565b61ca113b5b50600d604051146100905760005061009b565b60006000600061ca113c5b600e604051146100ac5760006100b1565b61ca113f5b506015604051146100c35760006100d5565b6000600060006000600061ca11611000f15b506016604051146100e75760006100f9565b6000600060006000600061ca11611000f25b5060176040511461010b57600061011b565b600060006000600061ca11611000f45b5060186040511461012d57600061013d565b600060006000600061ca11611000fa5b50601f6040511461014f576000610164565b6000600060006000600064ca1100ca11611000f15b5060206040511461017657600061018a565b6000600060006000600063ca110100611000f25b5060216040511461019c5760006101ae565b600060006000600063ca110100611000f45b505a60205261022a60205160005103036000556024356040525a6000526001604051146101dc5760006101e1565b610100545b506002604051146101f4576000506101fb565b6005610100555b600b6040511461020c576000610211565b61ca11315b50600c60405114610223576000610228565b61ca113b5b50600d6040511461023b57600050610246565b60006000600061ca113c5b600e6040511461025757600061025c565b61ca113f5b5060156040511461026e576000610280565b6000600060006000600061ca11611000f15b506016604051146102925760006102a4565b6000600060006000600061ca11611000f25b506017604051146102b65760006102c6565b600060006000600061ca11611000f45b506018604051146102d85760006102e8565b600060006000600061ca11611000fa5b50601f604051146102fa57600061030f565b6000600060006000600064ca1100ca11611000f15b50602060405114610321576000610335565b6000600060006000600063ca110100611000f25b50602160405114610347576000610359565b600060006000600063ca110100611000f45b505a60205261022a60205160005103036001556044356040525a60005260016040511461038757600061038c565b610100545b5060026040511461039f576000506103a6565b6005610100555b600b604051146103b75760006103bc565b61ca11315b50600c604051146103ce5760006103d3565b61ca113b5b50600d604051146103e6576000506103f1565b60006000600061ca113c5b600e60405114610402576000610407565b61ca113f5b5060156040511461041957600061042b565b6000600060006000600061ca11611000f15b5060166040511461043d57600061044f565b6000600060006000600061ca11611000f25b50601760405114610461576000610471565b600060006000600061ca11611000f45b50601860405114610483576000610493565b600060006000600061ca11611000fa5b50601f604051146104a55760006104ba565b6000600060006000600064ca1100ca11611000f15b506020604051146104cc5760006104e0565b6000600060006000600063ca110100611000f25b506021604051146104f2576000610504565b600060006000600063ca110100611000f45b505a60205261022a602051600051030360025560006101005500 +6cadb6f3a62c200c81a7378892323783816d7068bebe6ca080e977e7fe6ea9b1=60005400 +2afe2e927e087bca920ee4388e1a1caa75d5ce04fdfa0f164270fb137f408690=6160a760005500 +68b20d5b96763b7489bd3df7f0f15964ba9da3a41b3a076c78e55b07888800be=61acc73100 +a71f6a1b86265e6f47951c78ddd519cd1066f371af24825dc1fb4d75ebeb6a7a=6110313b00 +5ee7e88ac4216ad863574bca8316cd4d8a97302fa1011df7564f0531d2088fc3=6020600060006110313c00 +b1e315615c4fe2aff70d0dec7b92a74c368cd109fb0627ff55523b5c976dd7ad=6110313f00 +36655fa4a2cbd269eb3f61328dc9c1c428053759c6171e46e485e24c989930d2=6000600060006000600061acc76106a5f100 +b378df74ad6c112e42d456fcc41f6106bcae8ef9ec20b4a839e2d04b2cd18413=6000600060006000600061acc76106a5f200 +d6e77f0711387361b893496d41ead906f792186262e8b915937c69ff3b1cc58a=600060006000600061acc76106a5f400 +80d4e375cedb3013a6a033207f239d807a4e0ab396df4b2e48aceba1cbf8972a=600060006000600061acc76106a5fa00 +21d3705d2c47b6a1139bfe4612b4e9e8a87c5eb0b51e2d37ffef86021c2c5c36=60006000f300 +be2c379d12f13b7dc1bb1058900c04bfff2c8ccb54e8bc66a8d7e975d63a115c=60006000600060006000600435602435f160005500 +dd2d14d3db6f54c3ec32cc69822bf9e5622bc126651c6dc68fb601a81f4dbdc6=60f860020a600035046102005261ffff60e860020a6000350416610340526011610260525b61026051156076576001610260510361026052606161022051610100600001015360da600161022051610100600001010153607a60026102205161010060000101015360036102205101610220526024565b6102005161022051610100600001015360006001610220516101006000010101536002610220510161022052601b806100fa6000396102405260026101000260006000f0610280525a61030052600060006000600060006102805162010000f1505a610320526103405160b961032051610300510303036000556103405160015500fe61010061010060000161010060000139610100610100600001f300 +1cbb73464caef39ce3c526db024595fcba71c86b1bf9589c71c4c715abb90188=6004356000526024356020525a60405260005160020a505a606052602051606051604051030360005500 +e9ff5b4e35310a4db7bf1e57e31500cb90660489a3e97918c1fec9b4fb72f96e=60f860020a600035046102005261ffff60e860020a6000350416610340526011610260525b61026051156076576001610260510361026052606161022051610100600001015360da600161022051610100600001010153607a60026102205161010060000101015360036102205101610220526024565b6102005161022051610100600001015360006001610220516101006000010101536002610220510161022052601b806100fb6000396102405260026101000260006000f0610280525a61030052600060006000600060006102805162010000f1505a610320526103405161031161032051610300510303036000556103405160015500fe61010061010060000161010060000139610100610100600001f300 +78f3d15f369320cc54e0b87fbc238bc53f10b64388c404dc9dea660dc9808ef4=5a6000526000600060006000600061010062010000f1505a60005103602052600160043514602e57600050604e565b5a6000526000600060006000600061020062010000f1505a600051036040525b600260043514605e57600050607e565b5a6000526000600060006000600061030062010000f1505a600051036040525b600360043514608e5760005060ae565b5a6000526000600060006000600061040062010000f1505a600051036040525b602435602051604051030360005500 +f6d51341ea8ff5d63518d0c149659312d49040689acb30b26d9a6a11e272946f=60206004351461001157600050610021565b5a600052602435600020505a6020525b60376004351461003357600050610045565b5a6000526024356000610100375a6020525b60396004351461005757600050610069565b5a6000526024356000610100395a6020525b60a06004351461007b5760005061008a565b5a6000526024356000a05a6020525b60a16004351461009c576000506100ad565b5a60005260016024356000a15a6020525b60a2600435146100bf576000506100d2565b5a600052600260016024356000a25a6020525b60a3600435146100e4576000506100f9565b5a6000526003600260016024356000a35a6020525b60a46004351461010b57600050610122565b5a60005260046003600260016024356000a45a6020525b604435602051600051030360005500 +108ec940b9d464f35a336dae64e232fcba68a7bad78244a0bfcaf42e6e864328=6160a7600035526000355100 +b0702c57d75bd069c280b7217348f9d82f17b87412b97a9e2c4a80676c07e6ee=6160a76000355260003551506000355100 +6064cbcac253ea0412f09888f5bba7789e546214da264d3534595dc235469d28=6160a76000355260003551506160a76000355200 +bdb827e662459ec341da93cd7987ae9ab769a2bc62cb7744521b357ea92f08c3=60043560005260243560205260443560405260006000511461002357600050610031565b5a60605260205151505a6080525b60016000511461004357600050610053565b5a6060526160a7602051525a6080525b60026000511461006557600050610074565b5a60605260ff602051535a6080525b600360005114610086576000506100ac565b5a6060526000600060206020600061ba5e62010000f1505a6080526080516060510360a0525b6010600051146100be5760005061010a565b5a6060526000600060206020600061ba5e62010000f1505a6080526080516060510360a0525a606052600060006020602060006210ba5e62010000f1505a6080526080516060510360c0525b60116000511461011c57600050610168565b5a6060526000600060206020600061ba5e62010000f1505a6080526080516060510360a0525a606052600060006020602060006211ba5e62010000f1505a6080526080516060510360c0525b6002600051111561017b5760005061018a565b60405160805160605103036000555b60036000511461019c576000506101a7565b60405160a051036000555b60f0600051166010146101bc576000506101cb565b60405160a05160c05103036000555b00 +a564c77866beb770e7d04eb1e7b69e1f793642c45d1ceae9b048e4e8700c3554=6160a76000526160a76020526160a76040525a6000526000600060006000600061010062010000f1505a600051036020525a6000526000600060006000600061020062010000f1505a600051036040526040516020510360005500 2dcf6179fae46b73a6e1bb6fe062d56b0fa0ec2971b529dc5ae814ae4f28d200=5a6000526000600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f1505a6000510360645500 566a2fb3788518dcdbf2b4e84b1242016e317bea37cffb8e50d7d02d940daa2b=5a6000526000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f1505a6000510360645500 1857e39f8922c5c728afc24a2dddb22a1e865a4c101b873e6ee67f639cccac55=5a600052600c60000a6001555a600051036002555a6000526000600c0a6003555a600051036004555a60005267ffffffffffffffff60000a6005555a600051036006555a6000526fffffffffffffffffffffffffffffffff60000a6007555a600051036008555a6000527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60000a6009555a60005103600a555a600052600067ffffffffffffffff0a600b555a60005103600c555a60005260006fffffffffffffffffffffffffffffffff0a600d555a60005103600e555a60005260007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a600f555a6000510360645500 c30b60a297bc114822c8e14df3c876c56add3a4182cf7b987477a5fbef3a6553=5a60005273c94f5374fce5edbc8e2a8697c15331677e6ebf0b3b6001555a6000510360645500 -91e8abf25e107edb430c758a636574a9856b877250a7716180702eb337fc6b0a=6000600060006000600073ee098e6c2a43d9e2c04f08f0c3a87b0ba59079d46000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b6000f100 a19fa2b72a0cc97f6e79cad016c5e9496b86ee450244d51285ba2941cb87ce2b=5a00 -0d3135ebc4586f22e79775adca28a939f1dad92378cc4e56b65d2748ab8ddb29=604060006040600060006000355af200 +91e8abf25e107edb430c758a636574a9856b877250a7716180702eb337fc6b0a=6000600060006000600073ee098e6c2a43d9e2c04f08f0c3a87b0ba59079d46000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b6000f100 +f15d8dd53de81966c3c53f458e7c59bf8ea1a492e92c282f371ccb6b17d67336=60206000f3 +010911570642c8263ecf3e4b9962fd621db6b14ead00e43a01038c8946240fd6=6001600055600060006000600061271073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af150 +6837614816f00cdf8a34c7089b92ccfb445c85d3ae39fe52254ad886233e23c6=6001600055600060206000612710f550 +f2adcfff8511f649415782700392d85ad868bce9be6bf4cb8182906811455113=600160005560206000612710f050 +1069c043580db2ae345628d5f35ae22d30dd303007850a0bc1c2ef218d351591=6001600055600060006000600073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af450 +a54dac63f58da9143c7a638921f297db39e67ce2e3ced0e395b20430d1e3d0fb=600060006000600061271073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af150 +38500297ffe27de5ec2ee4eaf8acff775637bb8d7f745de2a72837e045571252=600060006000600073d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05af450 a335dc68decf7ac526505bee581c3669f6b925204dac27ed9a4661dce408ea2d=600060006000600073dead00000000000000000000000000000000000162028488fa60005573dead0000000000000000000000000000000000013f60015500 -c582eff643ca49efe39fc279b4bd43c2e150e59b643c69470116f65ce1f5f7d1=6000600060006000600073dead00000000000000000000000000000000000162028488f160005573dead0000000000000000000000000000000000013f60015500 b0186d1f0fb83cab30598535b1d61a06b4d5b7d4f30f54ce0baa5c36b6168a5c=6025ff00 e4d13dbb224dfb3c5baa06f80b928b029ae49a326d7f4dc4931dcd2e18fe1b74=6000600060006000600073dead00000000000000000000000000000000000162028488f260005573dead0000000000000000000000000000000000013f60015500 +0d3135ebc4586f22e79775adca28a939f1dad92378cc4e56b65d2748ab8ddb29=604060006040600060006000355af200 +c582eff643ca49efe39fc279b4bd43c2e150e59b643c69470116f65ce1f5f7d1=6000600060006000600073dead00000000000000000000000000000000000162028488f160005573dead0000000000000000000000000000000000013f60015500 07f57c2882d785f5e00721021ade0111a4ad7f5731d8e446856cb5f81b811b0a=600060006000600073dead00000000000000000000000000000000000162028488f460005573dead0000000000000000000000000000000000013f60015500 +2fbb4625057c201a4e9d2f25d41fc8231f598df1013a01cc5a8d38747f8d9878=60206000600073a2220000000000000000000000000000000000003c60005160105573a2220000000000000000000000000000000000003b60115573a2220000000000000000000000000000000000003f6012556000600060006000600073a22200000000000000000000000000000000000061c350f260135560206000600073a2000000000000000000000000000000000000003c60005160205573a2000000000000000000000000000000000000003b60215573a2000000000000000000000000000000000000003f6022556000600060006000600073a20000000000000000000000000000000000000061c350f260235560206000600073a3000000000000000000000000000000000000003c60005160305573a3000000000000000000000000000000000000003b60315573a3000000000000000000000000000000000000003f6032556000600060006000600073a30000000000000000000000000000000000000061c350f26033556020600060006000600073a10000000000000000000000000000000000000062086470f15060005160405500 +9655ae0666d5d46da6ef913c73b969ffdd36c5adb6f19bfe83c6bfbe47f1568f=6000603980601a60003960006000f560005260206000f30000fe60206000600039600051605055303b605155303f605255600060006000600060003061c350f23b605355602060006000303c60005160545500 9ca0496aae91e1731ba9206528d4f74d68fde12268034ea60bbc8ef1515a35f5=6000600980605660003960006000f5600055730826562ac9373818f7a055166f7b0cc87485f05d3f600155600980605f60003960006000f0600255737c5a2c91b22d7a9226523d4ba717db6afb741ebd3f60035500fe621122336000550000621122336000550000 -68ff1831256501f492cf7e85526c3b0e356d95fa9ca755db1f3714349b04f050=73deadbeef000000000000000000000000000000013f60005260206000f300 +a4fbeda2cbcf05ec8006868a4fbdc7fddb21025b64787a034e9cf6914ee05dcc=73c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783f60005573c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783b60015560206000600073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783c6000516002556000600060006000600073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa7861c350f26003556000603d8061010a60003960006000f5600a5573c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783f60045573c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783b60055560206000600073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783c6000516006556000600060006000600073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa7861c350f26007550000fe73dddddddd000000000000000000000000000000003b6000526000516000602073dddddddd000000000000000000000000000000003c6000516020f300 +e4c17df96db7198923adbb3613fb06daf08df364dd4eaefea23f979186b7924d=600b60505500 +95183626289cdbfa130461f01fb5ee4ae4d23be5f00d01c23bb05af0ca8f5351=61138874010000000000000000000000000000000000000000600173e713449c212d891357cc2966816b1d528cfb59e03c600051600055602051600155600c74010000000000000000000000000000000000000000600173e713449c212d891357cc2966816b1d528cfb59e03c600051600255602051600355600c6005600173e713449c212d891357cc2966816b1d528cfb59e03c60005160045560205160055500 +2d0cf6140026af1f0213a68d34f448b9306a3cc97efdec0cd7b850b68817ce46=600c606355600b606355600a60635500 +156633606cec03dd7aa5cbba790a1391e1d3cf2eaecfad59f006d7480258ee68=6020600060006000600073deadbeef00000000000000000000000000000000620249f0f1506020600060003e6000516000556020600060006000600073aeadbeef00000000000000000000000000000000620249f0f1506020600060003e60005160015500 +82651f83a3f20bc5f22127f2f83e9e046389754ea52cbffeff2615a12d326cf5=73deadbeef000000000000000000000000000000013f60005260206000f300 +7d479463e5816548703f295fb2cc82613af84454eb6d339fe3ed819215d2212b=73deadbeef000000000000000000000000000000013b60005260206000f300 fd3a9c1e19e63f147b68a35c11172ee7136a4310e5d938cf45faf4b24146e5e9=6020600060006000600073deadbeef00000000000000000000000000000000620249f0f2506020600060003e6000516000556020600060006000600073aeadbeef00000000000000000000000000000000620249f0f2506020600060003e60005160015500 +68ff1831256501f492cf7e85526c3b0e356d95fa9ca755db1f3714349b04f050=73deadbeef000000000000000000000000000000013f60005260206000f300 62d393661b8ff460bab64febc392284589fd4a4cff568e32c3c13de085552b74=73deadbeef000000000000000000000000000000013b60005260206000f300 b6b7e12f5a976593684d319b348150b69549ce23fb21eaaf5b71a2e7f8730bf6=6020600060006000600073deadbeef00000000000000000000000000000000620249f0f1506020600060003e6000516000556020600060006000600073aeadbeef00000000000000000000000000000000620249f0f1506020600060003e60005160015500 e483c6077f21978e25ee7e35054786b2a769babf998f275b37370e99df528c8d=73deadbeef000000000000000000000000000000013f60005573deadbeef000000000000000000000000000000013b60015560006000600060006103e873deadbeef0000000000000000000000000000000162010000f15073deadbeef000000000000000000000000000000013f60025573deadbeef000000000000000000000000000000013b6003550000 @@ -1835,11 +1746,48 @@ e483c6077f21978e25ee7e35054786b2a769babf998f275b37370e99df528c8d=73deadbeef00000 e97038d7744e13973fea10b3cb18be46c730a143278d1c29634e9a53e97df49a=6000600060006000600073deadbeef0000000000000000000000000000000062020000f15073123f4c415171383dcf6f3ac6c3b70fe321e11b5e3f60005573123f4c415171383dcf6f3ac6c3b70fe321e11b5e3b6001550000 879ed9782e7df695eb1378302c2afc5d4cf3205d33b6f55ac16b9cb4c56f705b=6010601180604260803960806000f56000526000513f6000556000513b600155600060006000600060005162010000fa506000513f6002556000513b6003550000fe600480600d6000396000f300fe6000ff00 42089f990b3c2c84f6729ade118838361de3d0b919dad3f836fc7a306604a6a6=602060006000600073deadbeef00000000000000000000000000000000620249f0f4506020600060003e600051600055602060006000600073aeadbeef00000000000000000000000000000000620249f0f4506020600060003e60005160015500 +0ae2ecd8658361e0d64b2b6f56421e2ebf4c07b951404ae95a65022c8ca1b6e3=6020600060006000600073bbbbbbbb000000000000000000000000000000006203f7a0f100 +9f2eb0a8e0c911d5ec4a041b9ea2db3d2937d9c7388e2807405072ca0403a7ba=73deadbeef0000000000000000000000000000000031ff00 +92d2e00b318f9112d293ddfc191b9d87424abbea060852673dfd2888af907cab=73aaaaaaaa000000000000000000000000000000003f60015573aaaaaaaa000000000000000000000000000000003b6002556002546000600073aaaaaaaa000000000000000000000000000000003c6000516003556020600060006000600073aaaaaaaa00000000000000000000000000000000620249f0f15073aaaaaaaa000000000000000000000000000000003f60045573aaaaaaaa000000000000000000000000000000003b6005556005546000602073aaaaaaaa000000000000000000000000000000003c60205160065500 +043e3d6fb9685268be63cdf84e86eaaeb3fc543b2ca60425048dc8591194db56=60016000526020600060206000600073bbbbbbbb00000000000000000000000000000000620249f0f1506020600060006000600073aaaaaaaa00000000000000000000000000000000620249f0f15060046020526020600060206020600073bbbbbbbb00000000000000000000000000000000620249f0f100 +828eeb4da96fff471230043ed4289f9a598aeb83df5f6057b21bd991a8871010=6020600060003773aaaaaaaa000000000000000000000000000000003f6000515573aaaaaaaa000000000000000000000000000000003b602052600160005101600052602051600051556001600051016000526020516000604073aaaaaaaa000000000000000000000000000000003c6040516000515500 +f58f838b381094e82d12bf31c614154e75ecedeb47e8fc0b32f011b7a6bed3e3=6000603d80604060003960006000f56000526000516000556020600060006000600073bbbbbbbb00000000000000000000000000000000620249f0f1500000fe73cccccccc000000000000000000000000000000003b6000526000516000602073cccccccc000000000000000000000000000000003c6000516020f300 +ccfa550acd1a0f11ec0ae707de2dfc091316d8d6fa18fe10c0e2e115fbadae31=73554e36262c0e0ab156397c32444e4a018fe93b183f60015573554e36262c0e0ab156397c32444e4a018fe93b183b6002556002546000600073554e36262c0e0ab156397c32444e4a018fe93b183c6000516003556020600060006000600073554e36262c0e0ab156397c32444e4a018fe93b18620249f0f15073554e36262c0e0ab156397c32444e4a018fe93b183f60045573554e36262c0e0ab156397c32444e4a018fe93b183b6005556005546000602073554e36262c0e0ab156397c32444e4a018fe93b183c60205160065500 +086be740a19075703d33033a48fc36bfaca06932b9838174cdb13596204b3947=73bbbbbbbb00000000000000000000000000000000ff00 +408a562eb813a73179c94815a10bf9def8a3303896fe86539564b9363664147d=6000603d80609460003960006000f560005260005160005560016020526020600060206020600073bbbbbbbb00000000000000000000000000000000620249f0f1506020600060006000600073cccccccc00000000000000000000000000000000620249f0f15060046040526020600060206040600073bbbbbbbb00000000000000000000000000000000620249f0f1500000fe73dddddddd000000000000000000000000000000003b6000526000516000602073dddddddd000000000000000000000000000000003c6000516020f300 +0b7c0870cf253e2e52d09afa2c863a1140ee7147134e0255ffe5c68cd7279a80=6020600060003773c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783f6000515560016000510160005273c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783b60005155600051546000602073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa783c6001600051016000526020516000515500 +f3c547f2d167f22c65e5584388488d46193e5cd03fe38010c5adb2706fda659c=6020600060006000600073c5691dc90d9fd2a2e9a5fa5bd28bf77ffd60aa78620249f0f100 +18af502ae688402469f027e81aa65fdde2a9e7a7ff025122eed8a4c063c6f46c=6020600060006000600073deadbeef00000000000000000000000000000000620249f0f1506020600060003e6000516000556020600060006000600073deadbeef00000000000000000000000000000001620249f0f1506020600060003e6000516001556020600060006000600073deadbeef00000000000000000000000000000002620249f0f1506020600060003e6000516002556020600060006000600073aaaaaaaa00000000000000000000000000000000620249f0f1506020600060006000600073deadbeef00000000000000000000000000000000620249f0f1506020600060003e6000516003556020600060006000600073deadbeef00000000000000000000000000000001620249f0f1506020600060003e6000516004556020600060006000600073deadbeef00000000000000000000000000000002620249f0f1506020600060003e60005160055500 +1611e769f69ab5ea50b2a478324e220f95634efdff41fccd0f5756dcd54656d2=73deadbeef00000000000000000000000000000000ff00 +cd07c35a0f2ade8591cb7085f0e087d671b9cd85a69cef2ab0ad8b7199fb36ea=73aaaaaaaa000000000000000000000000000000003f60005260206000f300 +864503b1dcaaea0f3951ded9c503c88878fbebfeabae04a863eef4a3f4145597=73aaaaaaaa000000000000000000000000000000003b60005260206000f300 +4d2137adbf52e88c643f245fc1bc65e43876b17562b4c830018d8fff22381d51=73aaaaaaaa000000000000000000000000000000003b6000600073aaaaaaaa000000000000000000000000000000003c60206000f300 ee5c44641dd7f8bb72a47e82d83d9be33c424ed7721eeee795fc96d2593d3481=6000353f6000556000353b60015500 +feb9ba92c6e4987a294d23df9744fa757212a3569df905c03675e5b2d6dae93e=73b94f5374fce5edbc8e2a8697c15331677e6ebf0b3f60005573b94f5374fce5edbc8e2a8697c15331677e6ebf0b3b60015500 +e1991ac4134897e9ab2d8767c5831f37c9e21878c52c0c2385429aa4849430f7=6000603380601360003960006000f5500000fe73b94f5374fce5edbc8e2a8697c15331677e6ebf0b3f60005573b94f5374fce5edbc8e2a8697c15331677e6ebf0b3b60015500 +7fc9647cf87ded7c494798bc9c4ae8ae10126514eda49aa547ef5b4c9504b553=6020600060006000600073aaaaaaaa00000000000000000000000000000001620249f0f1506020600060003e6000516000556020600060006000600073bbbbbbbb00000000000000000000000000000001620249f0f1506020600060003e60005160015500 +fcb86f532570aa508b4b2fe50b1a268b50c28af1c9b2f7f11bbd9b5d4a7108cb=73cccccccc000000000000000000000000000000013f60005260206000f300 +70f9d1dc42537e347b0aad1e48734d7c5b89ce868248fc959bfe7ba3efb14370=73cccccccc000000000000000000000000000000013b60005260206000f300 085197f0aca112afe5274c31d80185b1b604093ed5ce473274e7a543d030d817=6010600c80602360003960006000f56000526000513f6000556000513b6001550000fe61123460005260206000f300 +bbe3fa01181a4a0615a111139886adf19f511c037420c7ae6e99482202bebcbe=60146000600c376000513f6000556000513b60015500 3ba105638f941d6a45823f409e98431cf6eeff90e8f29c6a949376bea30ed527=602060006000600073deadbeef00000000000000000000000000000000620249f0fa506020600060003e600051600055602060006000600073aeadbeef00000000000000000000000000000000620249f0fa506020600060003e60005160015500 7edca4863e058b7266993e34fabed65e0a2ac99a0244b6b8ffa1d34d6323e7ca=73deadbeef000000000000000000000000000000003f60005573deadbeef000000000000000000000000000000003b60015500 78f85a8c778e9777f65d991884437d144223eb973b5e91f16ddd3db69ff39ef0=6010601080601360003960006000f5500000fe303f600055303b60015560006000f300 +055140c6d9067f8553c5279a5e7821eeb89ca0ec96695327d5fae5cf8cb99581=6020600060006000600060003562055730f2506000513f6001556000513b6002556020600060006000513c6000516003556000600060006000600060005161c350f260045500 +6d8dd42955eb665907b6d83c09986ac833dba5f76d0ff2eb3f2d3f1537367ef7=6020600060006000600073a000000000000000000000000000000000000000620249f0f15060206000f300 +381d0e3467807a361f8118519f140d91043bc86b0b4d4513fb872b20a430cd04=6020600060006000600073a000000000000000000000000000000000000000620249f0f25060206000f300 +325817e52f6d498947d394c35c2a5ff2ae3bbc4608913c4ab62993731075c337=602060006000600073a000000000000000000000000000000000000000620249f0f45060206000f300 +e78e7ed3a031fffd0f93434c9934304caf27821646b46df02187aa50bec7bc17=6020600060006000600073a100000000000000000000000000000000000000620249f0f15060206000f300 +82f26dab2ff2c1a8f80ef4512d509c8d9528c8b3c8fcf65f9eb5e8f046633186=6020600060006000600073a1000000000000000000000000000000000000006203d090f25060206000f300 +7b8f2d0584992c5da29e6c880b7b64555eebd27428de82c0d96a762341d1bb31=602060006000600073a100000000000000000000000000000000000000620249f0f45060206000f300 +a72e2aa34cb8d9f92381ab1a36fec6eac4ad9b0c0d91592b7ecc0f65650d0b1d=6000600f80601a60003960006000f560005260206000f30000fe6460206020556000526005601bf300 +799365042a307078377de2db3802dfefa07ec7a599f1c63f4c5e14c7a9851ef0=6000600f80606060003960006000f56000526001600155600160025560016003556001600455600160055560016006556001600755600160085560016009556001600a556001600b556001600c556001600d556001600e5560206000f30000fe6460206020556000526005601bf300 +f03594332b62b58c93f9a40e4f016d0b5b231c281d02d40f90e392059c271282=73a0000000000000000000000000000000000000003f60015573a0000000000000000000000000000000000000003b60025560206000600073a0000000000000000000000000000000000000003c6000516003556020600060006000600073a00000000000000000000000000000000000000062055730f15073a0000000000000000000000000000000000000003f60045573a0000000000000000000000000000000000000003b60055560206000600073a0000000000000000000000000000000000000003c6000516006556020600060006000600073a00000000000000000000000000000000000000062055730f160075500 +fdf1fd2e2ea497dfc30f866c0d12248e8060596f528257c5d32600d08471cb76=6020600060006000600073c00000000000000000000000000000000000000062055730f200 +bd094dc7477b59ef7bd21bbaf8e4d9ce9a6d81b5c5ad7ccc6025291039f4d31f=73a94f5374fce5edbc8e2a8697c15331677e6ebf0bff00 +7fa3c91edd41dbaa226b62cca5db3bf012f1cab96cb93c7f543668dcdc23e965=61200060043511600f576000601f565b600060006000600060006004355af15b506004353b6000556004353f600155600054600060006004353c60005160025561200060043510604f576000605f565b600060006000600060016004355af15b506004353f6003555a6020526004353f505a6040526013604051602051030360045500 +593aa664748bb3ca37b087d66a3ac17dac23d7b077bda16cfd713e69ec7feb72=6006806021610100396020526020516101006000f06040526040513f60005500fe60006000f300 +8657c03f2755ab87cfa8db58f4d6b0583c3fde957e207ea9bd38c8cc83513e84=600680602a610100396020526160a76020516101006000f56040526040513f60005560405160015500fe60006000f300 dd02fdd4e748988a91ac9867e755b6f8277ae78148b7c52d1a49038a1e89d41e=60106001557f6001600155601080600c6000396000f3006000355415600957005b6020356000600052602060006000f000 4bb059f4e1345dc14b7c78bc80feaa1692e9497649f87ffabf46388594eb6685=600060006000f000 3bd024cae466ddb4233a9206e24ffd5bd102925b026f60975ed047df53d14a60=6b602060406000f0600c600055600052600c60146000f000 @@ -1851,10 +1799,11 @@ ee7da33709c19bd962eee68389c89314f6ec80137d3441cb78d6c111a4027308=74600c600055666 5919fd6b3b20a3221bcedf32b58e4042baff97aa8ef589555e11893a0ae2d61f=6b600c600055602060406000f0600052600c60146000f000 509b43ac8411dbf966c230b9f8dd35c152414b7be1c848a8bebb1da34cb58353=3060025560206000600039602060006000f000 c21ce7b52ab574f79ada30926ebda6e9f60641c8985aafee8dbaae36f687c35f=602060006000f000 +9697d016645564aeb2639c2d88c07e6954b66c78b4e4319d1030e7591481b591=600980601160003960006001f0500000fe621122336000550000 3ee127d91eea32240afe65fc76abd217b294a9645f1bb8dcbddda48bb07e9d57=60003560030260005260206000f300 b4387f4c142f0127da220e06eacce7c746b6bbee86fcab846173ebfb1f108f9b=60156000526020602060206000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b611b58f15060005160005560205160015560406000f300 -b02b73e0457e3cdff66bcdce1be234608caa8fb50cf3cf31086b54fe03ff5eab=6001601f6001601e600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6107d0f1506000516000556002601ef300 e3ec67bda76132618ccf43c96cb0cf44bcf28757f2c8595217290fd11e4a7988=60156000526001601ff300 +b02b73e0457e3cdff66bcdce1be234608caa8fb50cf3cf31086b54fe03ff5eab=6001601f6001601e600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6107d0f1506000516000556002601ef300 8902038f59677d0f2f76aec116db122a94b1b364cdadafb02af511ab035e30eb=60006000600060006017730f572e5295c57f15886f9b263e2f6d2d6c7b5ec66103e8f160005500 df423a926a6db526900013c97c1e27cec738a0c18a441b152adafb975c79e1c2=60006000a000 f6f233f954759153a90af5be5b90fdec95b9df6818174f60f0a0497bb0291117=7faabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd60005260017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa000 @@ -1901,10 +1850,13 @@ af46e2a08fed36c593cdbcf4a77deea38894b3153830afd9aa9eba3e21bf8c82=7faabbfffffffff 124fcf50ccfa30be7819c0294624af4141ec56a0fbe3cef8eafcf59f74e8fcfb=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060006000600060206000a400 03c7197907537821094c2c9ec149e4b6a34daafe08c5b90994b7351049920aee=7faabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd600052600060006000600060016000a400 d04d9233925cf1a3991f0848c9c7fe98a2984dd8dfdf09f76309330759eb2f0b=7faabbffffffffffffffffffffffffffffffffffffffffffffffffffffffffccdd60005260006000600060006001601fa400 -8a8c125d9b5464fae5a66f62bc3b2f269b2b63cc320b9ffd8dd6a1268ad840dd=60006000600060006017730f572e5295c57f15886f9b263e2f6d2d6c7b5ec6620186a0f160005500 9099ac46b6d1b8bcca509c307a59c927c57ef345e189ad99dd6caebff5649feb=60206000a067ffffffffffffffff5100 -8ccf19d65aab653a0aa9489691349aec03a45fa6cfc046110f327dec627084e8=630fffffff630fffffff630fffffff630fffffff60007310000000000000000000000000000000000000016707fffffffffffffff200 +8a8c125d9b5464fae5a66f62bc3b2f269b2b63cc320b9ffd8dd6a1268ad840dd=60006000600060006017730f572e5295c57f15886f9b263e2f6d2d6c7b5ec6620186a0f160005500 +399fe86cade164b82ac638f669b21249d01d6a52bb537fe65152c0737457eddf=63dead60a76000526101006000f300 +ac71ea1958b7e077fbfc3c8e16602315e0d77e77e36856e7d150c159266858da=63dead60a76000526101006000fd00 +46ce285cc3af557e8194e718100c3ae4c9c82b85b48cd9c7a9b891c902e2bb86=60043561012052602435610140526360a760a760005261010060006000600060006101205173ccccccccccccccccccccccccccccccccccccccc00161014051f16101005260005160005560003d116057576000506060565b602060006101603e5b6101605160015500 7d73b53969b64e0a95ec98b7562644ccd76661044d654aa5a5790dd8428bb4c6=60005460010160005500 +8ccf19d65aab653a0aa9489691349aec03a45fa6cfc046110f327dec627084e8=630fffffff630fffffff630fffffff630fffffff60007310000000000000000000000000000000000000016707fffffffffffffff200 064c87204cf39627b92357a24043959f79dbfac6a8f962672c5790969e86aff2=63ffffffff63ffffffff63ffffffff63ffffffff60007310000000000000000000000000000000000000016707fffffffffffffff200 584c831d0ad95dc1b1a2fa111cd90fb80e843c25b95f052ad877021b62e171c7=67ffffffffffffffff600067ffffffffffffffff600060007310000000000000000000000000000000000000016707fffffffffffffff2506fffffffffffffffffffffffffffffffff60006fffffffffffffffffffffffffffffffff600060007310000000000000000000000000000000000000016707fffffffffffffff2507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600060007310000000000000000000000000000000000000016707fffffffffffffff25067ffffffffffffffff67ffffffffffffffff67ffffffffffffffff67ffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff25067ffffffffffffffff67ffffffffffffffff67ffffffffffffffff67ffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff2507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff2506fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff200 5eedf45cf7035da00c6c38686d1b3773cb6d615a2826065c6c608906813459d0=600060006000600060007310000000000000000000000000000000000000016707fffffffffffffff250630fffffff6000630fffffff600060007310000000000000000000000000000000000000016707fffffffffffffff25063ffffffff600063ffffffff600060007310000000000000000000000000000000000000016707fffffffffffffff2506000630fffffff6000630fffffff60007310000000000000000000000000000000000000016707fffffffffffffff250600063ffffffff600063ffffffff60007310000000000000000000000000000000000000016707fffffffffffffff250600067ffffffffffffffff600067ffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff25060006fffffffffffffffffffffffffffffffff60006fffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff25060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffff200 @@ -1927,23 +1879,23 @@ fe915acef64713ed78a436609d597a9515a122a544222751638161e50026ea40=600164fffffffff f2e3f4df6f5b48738fe1a4dbd5aea8f72b4842797a0b5d207977b9654e8573fd=6001623fffff5200 0cae2e21896571f1d0482a40f66e06729ad32ae86e9440c19e452d563d593597=600167ffffffffffffffff5200 47a126462863e1fc487df67bab3df2089abfc71aa4b523f7b6782ae90825600b=60005063ffffffff5067ffffffffffffffff506fffffffffffffffffffffffffffffffff507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5000 -00d5de551ee7a5a4b93cfcfd0a3e939c901ba44f1121cb499f3f906f32307c78=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000f300 -eed3ff87a0d0c61b833776c14ef3fba65cc145a1bcc2a914d4226781c9ec623c=63ffffffff63fffffffff300 -89a733741df289bcde6ceec5cf1bea1bd3c58eadc58c72fed47657d554a23ecb=60006000f300 +386fe076c477ec967131a49281dbba375b51925bb4430042079e8915798b9348=67ffffffffffffffff6000f300 6a6e213b3e7eb57ceb0bb22c17e461767dcb28d94c1b903eb304dcf95bb41c61=6000630ffffffff300 -46a54a35478ad25df50ebc2b6f7550b25b7451b343fb8c1e08b141b4ce751547=600063fffffffff300 78905e9e7a45f8598e6b7867c3adc15240d24277e35d8c16f2db09cdc1544975=60006d0ffffffffffffffffffffffffffff300 -f1cc4f74ba159815e4fd2c1e19cc1dbac964dda4b45bf47ccfe0e029852358ef=63ffffffff6000f300 8408466c1816cc59b6b9fcec7e37aea7164604a0df94e1e30831c9423886c817=6d0fffffffffffffffffffffffffff6d0ffffffffffffffffffffffffffff300 -4134e61bba4b29954deb6977e3c14a40dafd92ddb73461f86413c2e18d0e4904=67ffffffffffffffff67fffffffffffffffff300 -3eb1e695975e52e7dd4f7afffe8b02fca385f966034c7be4ed277d9c596208ee=600060006000600060007310000000000000000000000000000000000000016707fffffffffffffff1600155600060006000600060007310000000000000000000000000000000000000026707fffffffffffffff1600255600060006000600060007310000000000000000000000000000000000000036707fffffffffffffff1600355600060006000600060007310000000000000000000000000000000000000046707fffffffffffffff1600455600060006000600060007310000000000000000000000000000000000000056707fffffffffffffff1600555600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600655600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600755600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600855600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600955600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600a55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600b55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600c55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600d55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600e55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600f55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff160105500 -ff821a70b5e78b13b36cf3e507408b602fdefa2af105e07b7f8ab49f1dd2ad3a=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff300 -b4d880e59c7c17bc74784c186bde67430d3ddb71a778a98eda8c7122d56b653c=6d0fffffffffffffffffffffffffff6000f300 +4c1bdd3575d4730e3f56181077c12ee35942e531c8bf25e5a917af08eae5539d=630fffffff6000f300 +00d5de551ee7a5a4b93cfcfd0a3e939c901ba44f1121cb499f3f906f32307c78=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000f300 +89a733741df289bcde6ceec5cf1bea1bd3c58eadc58c72fed47657d554a23ecb=60006000f300 d679f961d83db60ac5f3be30a471dda0a7670a8b011a9e6390e8cca98bec5b62=600067fffffffffffffffff300 0b89d04832122a7a3e9bff16f2c29dcd664ae3018605a456f43030cff862c3e6=60007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff300 -4c1bdd3575d4730e3f56181077c12ee35942e531c8bf25e5a917af08eae5539d=630fffffff6000f300 -386fe076c477ec967131a49281dbba375b51925bb4430042079e8915798b9348=67ffffffffffffffff6000f300 +3eb1e695975e52e7dd4f7afffe8b02fca385f966034c7be4ed277d9c596208ee=600060006000600060007310000000000000000000000000000000000000016707fffffffffffffff1600155600060006000600060007310000000000000000000000000000000000000026707fffffffffffffff1600255600060006000600060007310000000000000000000000000000000000000036707fffffffffffffff1600355600060006000600060007310000000000000000000000000000000000000046707fffffffffffffff1600455600060006000600060007310000000000000000000000000000000000000056707fffffffffffffff1600555600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600655600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600755600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600855600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600955600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600a55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600b55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600c55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600d55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600e55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff1600f55600060006000600060007310000000000000000000000000000000000000066707fffffffffffffff160105500 +eed3ff87a0d0c61b833776c14ef3fba65cc145a1bcc2a914d4226781c9ec623c=63ffffffff63fffffffff300 +4134e61bba4b29954deb6977e3c14a40dafd92ddb73461f86413c2e18d0e4904=67ffffffffffffffff67fffffffffffffffff300 +f1cc4f74ba159815e4fd2c1e19cc1dbac964dda4b45bf47ccfe0e029852358ef=63ffffffff6000f300 +46a54a35478ad25df50ebc2b6f7550b25b7451b343fb8c1e08b141b4ce751547=600063fffffffff300 +b4d880e59c7c17bc74784c186bde67430d3ddb71a778a98eda8c7122d56b653c=6d0fffffffffffffffffffffffffff6000f300 317476e600a0d257f84d0f46262ccfbc9acd728b996b9e560551ac22c4900860=630fffffff630ffffffff300 +ff821a70b5e78b13b36cf3e507408b602fdefa2af105e07b7f8ab49f1dd2ad3a=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff300 9af366a03b359821a8029b03699c4ab4e3bdc8ed02cab79a9cdf4a36fe915bac=6000545063ffffffff545067ffffffffffffffff54506fffffffffffffffffffffffffffffffff54507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5400 883a7f1d89643b1d3f3d73e32f11083eec85093215e3195184dce5cd758a89d1=600163ffffffff55600167ffffffffffffffff5560016fffffffffffffffffffffffffffffffff5560017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5563ffffffff60205567ffffffffffffffff6040556fffffffffffffffffffffffffffffffff6080557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101005500 ff631084ef91e3ef02af7701b65c7849f05e96278f62e502bce19f156459080b=6401773594005160015500 @@ -1953,9 +1905,14 @@ e2b739e3e9aee02a6540cdfc27b5b6cc26ab2c574857b23db6235f224f676592=600160005263fff 9e915990c251fb9a282d74e6fbaea9bc9d69565ddb7da2592dd0ba2b8326b408=63ffffffff6000f300 e82976f19147f4b453ca8b58f9be648e9c40de237fa944ce6cce004794db8a40=630fffffff630fffffff630fffffff630fffffff7310000000000000000000000000000000000000016707fffffffffffffffa00 c4685fdab5c0cb3684ee14a4f16fb05bdb7706f8122aa0fd95ecbd197894ca0e=63ffffffff63ffffffff63ffffffff63ffffffff7310000000000000000000000000000000000000016707fffffffffffffffa00 -266d50413b3526c6d6db3488bbe86c35500a9fca848732b9704a5a6573083583=67ffffffffffffffff600067ffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa506fffffffffffffffffffffffffffffffff60006fffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa5063ffffffff63ffffffff63ffffffff63ffffffff7310000000000000000000000000000000000000016707fffffffffffffffa5067ffffffffffffffff67ffffffffffffffff67ffffffffffffffff67ffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa506fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa00 f1e2e5150310bd12b688199b146ce34bf0e03758d5c911f0069a8cdcfbcb4292=60005460010160005200 +266d50413b3526c6d6db3488bbe86c35500a9fca848732b9704a5a6573083583=67ffffffffffffffff600067ffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa506fffffffffffffffffffffffffffffffff60006fffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa5063ffffffff63ffffffff63ffffffff63ffffffff7310000000000000000000000000000000000000016707fffffffffffffffa5067ffffffffffffffff67ffffffffffffffff67ffffffffffffffff67ffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa506fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff6fffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa00 c69e6a67ecbf69e8d1d465b762944371857db02d1485df69f2ec8ea24d98fccc=60006000600060007310000000000000000000000000000000000000016707fffffffffffffffa50630fffffff6000630fffffff60007310000000000000000000000000000000000000016707fffffffffffffffa5063ffffffff600063ffffffff60007310000000000000000000000000000000000000016707fffffffffffffffa506000630fffffff6000630fffffff7310000000000000000000000000000000000000016707fffffffffffffffa50600063ffffffff600063ffffffff7310000000000000000000000000000000000000016707fffffffffffffffa50600067ffffffffffffffff600067ffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa5060006fffffffffffffffffffffffffffffffff60006fffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa5060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7310000000000000000000000000000000000000016707fffffffffffffffa00 +02b70170ddbf89061c6a8c7bb91a023ca494b643c0d63ec0efa75ea1c07421ac=6101206000f300 +3c4e35c17317d029fa326f619b7d5fa854bfc5c5d207e3b040d4e284c6c47133=6000600055600035602035f300 +bb922568fe10ee323702caaa4c8124917ab343b391325751c5832d19f9d483f8=600035602035fd00 +6f115007fdaa7d7834c9436e0db9366b7e8e048c5168fe95a48d0ef41ff763e8=6000602435146100115760005061001f565b600a61202052610100612040525b6001602435146100315760005061003f565b600061202052610100612040525b60026024351461005157600050610062565b600a60000361202052610100612040525b60036024351461007457600050610083565b61100061202052610100612040525b600a60243514610095576000506100a2565b600a612020526000612040525b600b602435146100b4576000506100c1565b6000612020526000612040525b600c602435146100d3576000506100e3565b600a600003612020526000612040525b600d602435146100f557600050610103565b611000612020526000612040525b60146024351461011557600050610125565b600561202052600a600003612040525b60156024351461013757600050610147565b600561202052637fffffff612040525b60166024351461015957600050610169565b6005612020526380000000612040525b60176024351461017b5760005061018b565b60056120205263ffffffff612040525b60186024351461019d576000506101ae565b600561202052640100000000612040525b6019602435146101c0576000506101d4565b600561202052677fffffffffffffff612040525b601a602435146101e6576000506101fa565b600561202052678000000000000000612040525b601b6024351461020c57600050610220565b60056120205267ffffffffffffffff612040525b601c6024351461023257600050610247565b60056120205268010000000000000000612040525b602060043514610258576000610262565b6120205161204051205b5060376004351461027557600050610281565b61202051600061204051375b6039600435146102935760005061029f565b61202051600061204051395b603c600435146102b1576000506102c0565b6120205160006120405161c0de3c5b603e600435146102d2576000506102de565b612020516000612040513e5b60a0600435146102f0576000506102fa565b6120205161204051a05b60a16004351461030c57600050610318565b60016120205161204051a15b60a26004351461032a57600050610338565b600260016120205161204051a25b60a36004351461034a5760005061035a565b6003600260016120205161204051a35b60a46004351461036c5760005061037e565b60046003600260016120205161204051a45b60f06004351461038f57600061039b565b61202051612040516000f05b5060f1600435146103ad5760006103c3565b600060006120205161204051600061c0de611000f15b506101f1600435146103d65760006103ec565b612020516120405160006000600061c0de611000f15b5060f2600435146103fe576000610414565b600060006120205161204051600061c0de611000f25b506101f26004351461042757600061043d565b612020516120405160006000600061c0de611000f25b5060f46004351461044f576000610464565b60006000612020516120405161c0de62100000f45b506101f46004351461047757600061048c565b61202051612040516000600061c0de62100000f45b5060f56004351461049e5760006104ad565b615a1761202051612040516000f55b5060fa600435146104bf5760006104d4565b60006000612020516120405161c0de62100000fa5b506101fa600435146104e75760006104fc565b61202051612040516000600061c0de62100000fa5b5061013e6004351461051057600050610530565b61010061010060006000600061c0de611000f150612020516000612040513e5b60f360043514610541576000610557565b6000600060406120206000630f30c0de62100000f15b5060ff6004351461056a57600050610585565b6000600060406120206000630ff0c0de62100000f1503d6000555b60006101005500 +69ef859cd41eef96f85e18ea74d74942f1a2b7dd3aee4a24bd0c8f46d5e25c16=6000612040526000602435146100175760005061001e565b6000612020525b60016024351461003057600050610037565b6010612020525b60026024351461004957600050610051565b618000612020525b6003602435146100635760005061006d565b6010600003612020525b60046024351461007f57600050610089565b637fffffff612020525b60056024351461009b576000506100a5565b6380000000612020525b6006602435146100b7576000506100c1565b63ffffffff612020525b6007602435146100d3576000506100de565b640100000000612020525b6008602435146100f0576000506100fe565b677fffffffffffffff612020525b6009602435146101105760005061011e565b678000000000000000612020525b600a602435146101305760005061013e565b67ffffffffffffffff612020525b600b602435146101505760005061015f565b68010000000000000000612020525b60006044351461017157600050610178565b6000612060525b60016044351461018a57600050610191565b6010612060525b6002604435146101a3576000506101ab565b618000612060525b6003604435146101bd576000506101c7565b6010600003612060525b6037600435146101d9576000506101e7565b612060516120205161204051375b6039600435146101f957600050610207565b612060516120205161204051395b603c600435146102195760005061022a565b61206051612020516120405161c0de3c5b603e6004351461023c5760005061024a565b6120605161202051612040513e5b61013e6004351461025d5760005061027f565b61010061010060006000600061c0de611000f1506120605161202051612040513e5b60006101005560036024351015610298576000506102a5565b6000516000556020516001555b00 d51cb57b989ba090a0cbf6b685511c165594715e4d99c1b5371403761ea955e2=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052601061ffff60003760005160005500 e6b28b7ac5d98863f88da77283db86905cd8dc252edb0af65174b286b715353e=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052601061ffff60003960005160005500 5115aeb89b71d4f66c307880a9a6b2670fad106c93850b58a30349d8bfbbc119=602a6000535960005500 @@ -1998,126 +1955,49 @@ b2f34f8fd7351af42946f10cbcbaceabb764e90e0f230d4bde11fa12195ad688=602a61f9e053596 3128fa92bfdd224510dfdf841a34b464559eb1ab297d8f5d4c68c16514e1aae6=602a61f9df535960005500 936f52989634c9dc92d33ba901a5ac808bc9acd93db45d9b7eba773c496490fb=602a61f9de535960005500 d4f7e542342692e64b86707702652e79e04b253edfa91cdd1a6f0bbd3efbb0d8=602a61f9ff535960005500 +2008b8b4aea344d1383a53ece06a0db6166b4133f10877fdf922b9998cce5731=600460005b600f8110156020576011600182010281535b6001810190506004565b50600051600055600a6002600a60006000855af150600051600155600a600060203e60205160025550 c367c64d90ffa50458cf755dc5d10f83bc2d9d8250058d3d05b943468aefa07e=366000600037596000f300 7012bc42bb8026cf166f7326ed246b0f95e4f751c2e5cf9c08dad4f0d7047b2e=620100005160015500 0898f33abc8db9ff3da67ce0a69db61613ce641395635c11fa1517790e7d6dc7=6101005160015500 +a9e5d35726cf7d3f99d83c391100c936092c87831b690d033d14da5db51bf170=61100060002050 +9ef622c9b42196fe0519fda0941f998d4d99a6a175c9005b7097c2903217b31d=6110006000600037 +28913a4f566a2dc5e3ac457a4eaeccbf06bbefa53f18a652b15e10dfb271bfb9=6110006000600039 +5e2b9eeb0294a6acad85d6c1e76bdb6d37df823ec31f36660d850cd903ae67ff=61100060006000303c +55c5e2cef947d4612f1729e73b33e00c5ff964879895947e26937d916a5e939b=602060006020600060006201113e5af150601060006110003e +e499501e5bafbd1c361c20dc5a05e40c7d486d5ab46cf9e2cfd59346786b9b38=7f0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2060005260206000f3 +13d0233a2bd697f7398d45c35017fc346a4b6f6b9accef673effad9d91a5c92f=6110005150 +10cfa4256c7bf2c8801020effb7b4d90f16681520073bf48f4b0aaab4c3b70b8=60ff61100052 +91f0d33100b22a9bd9c157cab04280fa04458b2d4a576c62c29ef2e2c2a3b0c9=60ff61100053 +d6866c883a3e7eea46b19bfef13b70ad95230fc9616031850a1f76a45404b02b=602062010000a0 +3e99d08ba8ce62716fd008bcf8e8a3096f33291936b34b9a70d0e8168d580082=6001602062010000a1 +9330f139abdc003d8823459927dea2b0fabf4376a2233d0428b29dd6d092c724=60026001602062010000a2 +f1081eeac9c3907b631cda5f8182520dc2792412e7bc18a0341a9ad2c01df8a3=600360026001602062010000a3 +c15fc1157326db732bdd5e728ae4f8c71f30a379e40db53a60cd1a63e6b1a89b=6004600360026001602062010000a4 +b439c2fe865f899a9b489a5f79a04101534669e9d6b7051df6f16083dd5c160e=6020620100006000f050 +b4ba69d5a16b5e51f0e17fbfd2225ea8c2eb959a74162c79e3b85783dadd9fde=615a176020620100006000f550 +1b2290979cf403b8281ad39f910906c10e8953e8048d40dc38623dff8007c8b9=602062010000f3 +2ecc7534ab3ed062c9e731421cad45f819bb031262794a81addffc46def2fa03=600060006000620100006000620111f15af150 +26210b12ec0faac7a4d6c0d0b55aee7569965df3ff695be9895e27f6e3d7f533=600060006000620100006000620111f15af250 +d93eddd86ce9004dfd9651ee2531a49a39dd41e2e4335266970443a8c3fd841a=60006000600062010000620111f15af450 +187f3a42d83cff10533684fecfc325133b872195c7a3b8d777b2a70c670e2ad6=60006000600062010000620111f15afa50 +74137ced833d5efd3e225bc476c503830692634aa1932401210e2f8fb533e2fb=6004356024356000600060006000600086620100000186f16000555050 caf9facbed862fe613b3320022ed06b17a8dca8eacc2c73de4713f009ae469dd=5a6000526000600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f26001555a6000510360645500 c7a6d05c0caf2c88e24e84509b2b882162e24a3c66f8e17d5f0a9b93a7ee5e4b=5a6000526000600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f16001555a6000510360645500 4366d37cfc4ffc877c93c4b6b4c5c7334203a7532f95d17ed0b69f11c4817573=5a600052600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f46001555a6000510360645500 fb925c7db14644f0b02048be7db493a7c246711e6c7cade981323a33f9d839db=73c94f5374fce5edbc8e2a8697c15331677e6ebf0bff00 -dd3d0af7eddfb9529a6203d2f05e55b18b95124f9ac0d821eccb02acdaef7643=7f112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00600052602060106010600060006004620186a0f1503d60005500 -50f2bc99af0ab111aff4a7f3f4ab707a8f4e7b33592e29fc538dde24d7bbecbb=7f112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00600052601060106020600060006004620186a0f1503d60005500 -4abd67656bb73843482c12c6f98fc2a7a4bf31640c929046d81c71d73eb03dcb=36600060003760206103e8366000600060055af26001556103e85160025500 -002b05c9652e49f171604528da571a03d9a5990feba5f726269ee93be097c429=36600060003760406103e8366000600060095af16001556103e8516002556104085160035500 -c0b5fa48891069030b40fe40e055d9491149f8f86b98172ca254dcf8f65a3ee8=36600060003760406103e8366000600060095af26001556103e8516002556104085160035500 -16ab6d243da07ab056e0bc10fc1fb498267577fd9b7e39059e843bed3348682c=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f260025560a060020a60805106600055600054321460015500 -8668fce0ab1cb0aed47ad3371787b50609c053529f792fea04e95d328af9e150=602060806080600060006001620493e0f260025560a060020a6080510660005500 -ca510f737fd9700323d077daf4da6a3eb35d7fb1a422e1eccae9587179f0732d=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb7f260025560a060020a60805106600055600054321460015500 -d1862f884cbb20cc8ddbd72f858150ce83bed13bfe97922c9a5ec5d15a3e3744=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c45496060526020608060806000600160016000f260025560a060020a60805106600055600054321460015500 -d95492170624c3c081a0f3814042b06d027031eb5e81c02d09bd34c8265c3a31=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb8f260025560805160005500 -31463cec35e017fe129168096051af4682fbf88e07f0c4df16d6c02daf00a7bf=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb8f260025560a060020a60805106600055600054321460015500 -289890857c95552550cd2d3d6bbd5867957a97c603d4d0477c58acc303c0b83b=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060406080600060006001620493e0f260025560a060020a60405106600055600054321460015500 -3e037c07b0564c4eac48b68cc0b5f0a776d592f01bab4dd74176cdcfe63a5c78=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c60005260016020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620186a0f260025560a060020a60805106600055600054321460015500 -bc008be67c7bfe6b362775df5ba1efc54aa9f49d8a18a75b0824923c27b72b37=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6021527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549604152602060616061600060006001620186a0f260025560a060020a60615106600055600054321460015500 -b3b5f1340aa2b7d51b913ea1f3ec12c086efa61ef981d24eb30e72b99683fef4=7f2f380a2dea7e778d81affc2443403b8fe4644db442ae4862ff5bb3732829cdb9600052601b6020527f6b65ccb0558806e9b097f27a396d08f964e37b8b7af6ceeb516ff86739fbea0a6040527f37cbc8d883e129a4b1ef9d5f1df53c4f21a3ef147cf2a50a4ede0eb06ce092d4606052602060806080600060006001620186a0f260025560a060020a60805106600055600054321460015500 -977e8a3222fae420ce27d6b7c699c900fc668ce0d3169787f108837b3e80463f=7ec547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527eb1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527eb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f260025560a060020a60805106600055600054321460015500 -d291ab4a338f210afca4627d95b397c954e1b48daf27d0b736382bb370d9108b=7ec547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f260025560a060020a60805106600055600054321460015500 -ee94e91f457e04a3317499865eae21775809d90882a3300f503f75415c671d82=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527eb1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f260025560a060020a60805106600055600054321460015500 -9990b8b963677b292172c3bb50e89cd096346fb4b5f28795f8b3b404cd10ff7f=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527eb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f260025560a060020a60805106600055600054321460015500 -780b20b2ccc801ac90b85165d29662fe97e53ba823508baa89b05e621824977f=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f260025560a060020a60805106600055600054321460015500 -8cc2c43b1127ba04e6293a1c760514203f983fdf21f692311d0c481e69c61402=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c6000526000356020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f260025560a060020a60805106600055600054321460015500 -81ad4ef00bc21e8b6309f2ebfd0970d13c1f8d784e8a2fd1d237665716aeb32a=6020600060006000600060046101f4f260025560005160005500 -b53497172a62ce4698a24f23b23479898fdf94f713720e8203894238e85974a6=60206000600060006013600462030d40f260025560005160005500 -c81cb74548ba87e299451475d12e44c9d8b199296f6034b499659fe38c7f7c50=64f34578907f6000526020600060256000600060046101f4f260025560005160005500 -9ed9fb5823828f130dd646e6b3f504fb7ed45bc44697d61b74883532aa494016=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060046064f260025560005160005500 -b0b6448af3b43d97716de98ee8c58e1a3882c8307a5d39de2975836e85406fa1=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060046011f260025560005160005500 -82cc879d055884da3ada9e9441878183328787c3aa6aca089d39a2fd5a0a5224=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060046012f260025560005160005500 -8ae427636e68f9b1da17ee38d0dd7576270447a6fe3c4f1bc86b20e3ccce566d=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000620f4240600060006004610258f260025560005160005500 -8490f633ccadf51d4065d0cbe78e2e94c7fd39560d99114e077c6676a4229b15=602060006000600060006003610258f260025560005160005500 -5e8abba5114cb01677cdc5ffc41e641063145fc4b146f58098ac51e80dcc0db0=64f34578907f600552602060006025600060006003611770f260025560005160005500 -7121157ccc134d9028b8a3e5208cbf7b858bca0ab3ed9bfe487373de7b040533=64f34578907f600052602060006025600060006003611770f260025560005160005500 -d1b5e3f54af11e567fcc591d3fe7945a00bbbae19c4f5ac76fdb55c2bbbad01f=65f34578907f00600052602060006025600060006003611770f260025560005160005500 -413d16e68426085de5d92cb66784cb62b1808cdddf820c1d27765080db5a33ce=64f34578907f600052602060006025600060006003611770f260025560005160005500 -92d984a2a1d8416aaa39511c2f8f771cfcf30507a0953c54d9eb19722c751301=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060036102d0f260025560005160005500 -c86534a5d41bff75c80a455feb63f7106078f4fe6c0a8241fb97e8170dba33cc=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060036102cff260025560005160005500 -41aa8421e009e69ec9524a992313ec7059cd2aad028fcf636e327a552d8785d7=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000620f4240600060006003611770f260025560005160005500 -507a179b7e441c37058c378e759507b7189125466a98da0189c15ac1ce03804f=6020600060006000600060026101f4f260025560005160005500 -d29392cddb3c4ce92f7aea2304d57ce031d90fa1e4b489870ade9954a52c8464=60206000600060006013600262030d40f260025560005160005500 -5ca82c649045cc4829d1406b05f57ad224e0f49e4d2207125d85a283c7293ed8=64f34578907f6005526020600060256000600060026101f4f260025560005160005500 -40fbff202df0c6c0a6755ac27c59107ad6fe3ea0d39fff3a071aebc5c6c713f8=64f34578907f6000526020600060256000600060026101f4f260025560005160005500 -eca68dab29463a07f6762091f9aed2938f8b0724e20b9ccb8ceff5fde9f6f53f=65f34578907f006000526020600060256000600060026101f4f260025560005160005500 -f29ac53143de495686a7ab4bf3c8db7f7aa8f33d8a76f97cfd280585c7152b83=64f34578907f6000526020600060256000600060026101f4f260025560005160005500 -6210e7142957f1930aeba67b8aedd430584a6d1476a255508297a7f6de103b0a=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060026064f260025560005160005500 -c43d991ec309c80dfa38ab5aea103ce446a4be4d03a6a752b232726635c9e11b=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060026063f260025560005160005500 -b13f769f23c2d74410f3a413e585065037f9a4e209bf2422fb133f9c7f1cd7fe=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000620f4240600060006002610258f260025560005160005500 -7d2b7e2f357425f6999978b31f91519c03c2458c5318cb9565b9f78ebf135f61=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f160025560a060020a60805106600055600054321460015500 -8e64949ea03af0a2aff6857cdd517509e673f13781651ab7ab07947bcd202e46=602060806080600060006001620493e0f160025560a060020a6080510660005500 -a4b8f4ae438e05bda541eb74fbc840847dc6fed23870aef6bd873c41fe4e6483=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb7f160025560a060020a60805106600055600054321460015500 -caf0c06b41f19ebc5061a07c81547c4d4aa61940a13cb4c847542859b448b360=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c45496060526020608060806000600160016000f160025560a060020a60805106600055600054321460015500 -54fbde9f3261be7c370534c5b79077a46df33c97188d1b8e2714057bbd8a0241=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb8f160025560805160005500 -b810b163a9c7cfdc7bd8ab3ed6e23e4a988781a86bbdbace1a2af50056ed3d57=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001610bb8f160025560a060020a60805106600055600054321460015500 -f0f8ef774072703cc952b143c247eacea6320a0b840e932d41bada601b73f895=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060406080600060006001620493e0f160025560a060020a60405106600055600054321460015500 -b2e56633ee091daac610b3bc45b75ac566cf0129e1b081391d5f6481e4122495=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c60005260016020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620186a0f160025560a060020a60805106600055600054321460015500 -6aa3eb5b4de5a96845bd8ab0b48f9a5afab3755b6000b2ab49adc7da872634a7=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6021527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549604152602060616061600060006001620186a0f160025560a060020a60615106600055600054321460015500 -cb30118aaf974b06438ef93e6861ab84e33f7dabdd87f830f4f3055f53a1aede=7f2f380a2dea7e778d81affc2443403b8fe4644db442ae4862ff5bb3732829cdb9600052601b6020527f6b65ccb0558806e9b097f27a396d08f964e37b8b7af6ceeb516ff86739fbea0a6040527f37cbc8d883e129a4b1ef9d5f1df53c4f21a3ef147cf2a50a4ede0eb06ce092d4606052602060806080600060006001620186a0f160025560a060020a60805106600055600054321460015500 -bb307c2022e3eb441951455452274906698d48438e944962fbdd607d36ae1a0c=7ec547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527eb1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527eb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f160025560a060020a60805106600055600054321460015500 -b2827d871d504c860f9fe2c5b9f1eb89cc54e7c593cd26f4185a291eb4d77464=7f11223344556677889900112233445566778899001122334455667788990011226080527f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f16002556080516000555960015500 -571bd43ee9c4272ea91ac5fe9da9931491c5ccda475b565feb02f27d32ee6781=7f11223344556677889900112233445566778899001122334455667788990011226080527f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601d6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f16002556080516000555960015500 -ed9a70802f98412191b7eaf52ecd1655b4b46d77c1f16e6e714c5bce8b73275b=7ec547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f160025560a060020a60805106600055600054321460015500 -1e8adaa0e189c4b3ab4b4cabcf9149df6849fb940326ee6d128048c1c2e82f00=7f1122334455667788991011121314151617181920212223242526272829303132608052602060806080600060006001620493e0f15060805160005500 -bd94cbf291eeb3669079c541cc0cb78fa78659282b13201a23683a1f5159a663=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527eb1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f160025560a060020a60805106600055600054321460015500 -b6feb44aa94e71f069380b8a16fab16fab6639da188303b2dfd5884ce96feb87=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527eb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f160025560a060020a60805106600055600054321460015500 -87d548c2190744e4ae38a6c81395e1079b36b33f669c65237632d642c022a10e=7fa8b53bdf3306a35a7103ab5504a0c9b492295564b6202b1942a84ef300107281600052601b6020527f30783565316530336635336365313862373732636362303039336666373166336040527f66353366356337356237346463623331613835616138623838393262346538626060527f1122334455667788991011121314151617181920212223242526272829303132608052602060806080600060006001620493e0f15060805160005500 -9b45691c7b9b7c243685984105c83f7e59225b54f8d10a9fe9f1e001fd24e113=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602060806080600060006001620493e0f160025560a060020a60805106600055600054321460015500 -c0c51fdedf366524cf559c03f81fa0cc742cbba1991d562a2e6ddde3f4e8cf4b=6020600060006000600060046101f4f160025560005160005500 -d20aaaa70fd9c9d9fccb1e0c95a34cbc63e7e9b94888e4a94faaaa4187b8b124=60206000600060006013600462030d40f160025560005160005500 -45fb06f1fb4ed243224c9cf0f8ca5106762f375d22f5797a3f9c3391d413c997=64f34578907f6000526020600060256000600060046101f4f160025560005160005500 -ec39ee76400a8f7497c600ce0f9111d9404c6fd8346919480bba9770ec2f1736=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060046064f160025560005160005500 -b06db3acf10b8dfd3dfe6f6906840e0cdede0db7d69724bf03b52c51d176e397=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060046011f160025560005160005500 -5dda018bc76c5cbbc8d767d90c6b55d4e2a37c6a8416a3f70acb0d6581a119c7=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060046012f160025560005160005500 -0044163c07f1c33b1f31f4b54f7b822d42a7679ab21639387586b712255c8186=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000620f4240600060006004610258f160025560005160005500 -6c04a706c562cc337469377071a62c2ac0788cf7b1968cd1c7b51e4accb0bf11=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052611234602052604060006020600060006004610258f15060205160005500 -fc4c98a8ea67879fe4b147a87f21068947ebc2a2e14b460c863cd2ec221b44fa=602060006000600060006003610258f160025560005160005500 -e5919593a0e305b0e0a50330b8c1c988f9644ac8f178e9e988b76e531e86903e=64f34578907f600552602060006025600060006003611770f160025560005160005500 -56590609ed72bd51457aeec44e7c1b67c4e3f5c2a7b92cb7c9ebefda338d5954=64f34578907f600052602060006025600060006003611770f160025560005160005500 -82238321104790f239004a23812cd915baf468ccebd9dab577992b70b6ca07d0=65f34578907f00600052602060006025600060006003611770f160025560005160005500 -23a034567b665caa28c43986e4ff1d8cdeeff67cbf5e5e0836891e3d0d9e9591=64f34578907f600052602060006025600060006003611770f160025560005160005500 -989794a85580d247818c13ac38f1732e6b306895875d3314aabe4ee3c4da870b=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060036102d0f160025560005160005500 -c3c780c449cfb5d860a816939342be501c9d8306af07bcd82354d7850fa7c175=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060036102cff160025560005160005500 -731ef8b7b8b7f12f9be98c17120744f54b4f67a12d40a09668e7831172bed470=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000620f4240600060006003611770f160025560005160005500 -b46ad64073679fd5ef8aa29416b689e1de6f1bfb6a68adf0562a9ee5c3676de0=6020600060006000600060026101f4f160025560005160005500 -487e756b4ca1eec4b60416a5cb82a9e33e4f20fa0568f6a2a8a89a0f28b0f606=60206000600060006013600262030d40f160025560005160005500 -1dc31e5e0ad16890a156a0e06aabd983740047f365908b23ae893929728a9fe2=64f34578907f6005526020600060256000600060026101f4f160025560005160005500 -ffb062be6258b2f5d7ebdfa19a3a4a84f9bbbfcc8884bb554d965512208629a1=64f34578907f6000526020600060256000600060026101f4f160025560005160005500 -5abf96d293365bcda9721e484403373a969d37e434414d6d889825dca7b8c65c=65f34578907f006000526020600060256000600060026101f4f160025560005160005500 -16858d5b4bd249ae3f308636d30a3d7d68bcbf34dae43465b590d8f307bc0713=64f34578907f6000526020600060256000600060026101f4f160025560005160005500 -a82464224a2a8ad1ba5bca77c3f2a186ba15d1f26f78cfc663130063d4956351=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060026064f160025560005160005500 -c38cfee4eccdcddffd1dc5eb3d6943b18c8df3f0265cd65bd69c3aa44ef4f477=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000526020600060206000600060026063f160025560005160005500 -389b71c33fd461327f8a2d1fd3d70e46538e6ecc964239c655155e65b53a5d8d=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000620f4240600060006002610258f160025560005160005500 -9fc60d3839be8b6802e91ceb1b59fa4d88ca9d8d083dd5d095940d5a7c5ceda3=60016000540160005561040060005410601b5760016002556047565b60006000620f42406000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b620f55c85a03f16001555b00 -8e605e0326c801dd5e416e2b0967c232b8b3aea844215677ba18514e3556ffb1=5b603260805110156040576000600060006000600073aaa50000fce5edbc8e2a8697c15331677e6ebf0b64148c1c2280f16000556001608051016080526000565b60805160015500 -f19985fce537668effe9f9266836defa6ad3c9ff8ee83ecd682946cea6fd7299=5b61c3506080511015603f576000600061c3506000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b610640f16000556001608051016080526000565b60805160015500 -ac3f91c92008607a228393782f5d6908150b70098f44829124b693700ca44d9a=5b61c3506080511015602c576000600061c3506000600160016101f4f16000556001608051016080526000565b60805160015500 -e401216745e43083d3bd1fd33b6dcb0cac1e53db25be9c980fd0733111c8631e=602a6001525b61c350608051101560325761c350600161c35060006001600461061cf16000556001608051016080526005565b60805160015560015160025500 -412cf97224a528e3be3c36ae79e9f81cba3a8e7ae12d2f6492e1d55eb9ed9e15=5b61c3506080511015602c576000600061c35060006001600461061cf16000556001608051016080526000565b60805160015500 -b8dacb2ba97d2d55e056e6bd321f5f2463399416d56e7d6f1ec8077f0442e10b=5b61c3506080511015602d576000600061c35060006001600362013178f16000556001608051016080526000565b60805160015500 -a5fae387537355a51257a02460223a9c7983b1760793e9b92010a8d97102dd7c=5b61c3506080511015602d576000600061c35060006001600262013178f16000556001608051016080526000565b60805160015500 -1240495ce2d611a9bb2924333c27843b1f4fd7560e39a14bd2352d4b369a0359=5b61c3506080511015603f576000600061c3506000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b610640f26000556001608051016080526000565b60805160015500 -1a4e264aaf30374f0e52325977f07d6e808fcefaf2571ec0e58f0c2f207f00c4=5b6103e8608051101560235761c35060006001f06000556001608051016080526000565b60805160015500 -ce905ad58a1d41618146ae747022197518d1b787888432715683cfce8b72006c=61c350600060003700 -28944339552b4ea6f4172684054c69c3eb5bc8ace206281f4d5d5df6a28d6909=5b61c3506080511015603f576000600061c3506000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61061cf16000556001608051016080526000565b60805160015500 -9d91f037709001db2ab01f723fd2ef9e9da2f86d992d8376f9e5b9f247e751cb=600161c34f35f300 -f54f43e09582fed3a91cb9f7520d3a0ce19512ffbf23e9e986bd4af5da0febb3=61c34f356000526001600051f300 a7d9fc32b1d28671dcedc531029d203020bceb11e49db188e50421673bcf8f33=60206000600039602060006000f000 577962e61316730fa04134d6d75cef6e94babb54e9b145012418727548ea9618=602060006000396001602060006000f00160005500 72ca3096c3df1c11aafb22fc8ff4bc16504c712f41acfd649a796761c537ad0e=6000600155600060025560006003556000600455600060055500 4229b08ed719d199c4c377982ec057d87310f7ecc085aa0d9eb0acbca0d7c432=6001600a556001600b556000600155600060025560006003556000600455600060055500 f01c97341686169e115128bc4a55d9714e85d3f05bb3c2c5764afeb983e04c6f=600154506002545060ff60020a600a553031600b5560006001556000600255600060035560006004556000600555600060065500 044661348c230fea4bf2ff442a4422738b9b9ebbef430f09273aec57fec16952=600154506002545061ffff60020a600a553031600b5560006001556000600255600060035560006004556000600555600060065500 -4ded1eb002cb054874f2ea1996edd56bd3da577953433c9aaa702976cd608321=5a6016526001600a556000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa600035f1600b55600060015560006002556000600355600060045560006005556000600655600060075560006008555a6016510360175500 +b1ec84eb90eb693cdbff9a5ac86f8f729e3ef784bf36384c730ba39d1b10dda0=73ddddddddddddddddddddddddddddddddddddddddff +cd8bcc7a2b45eedecfdb09569a86e3148578de2e210b26bb4cf3f862bbd3a062=6000806000558060015580600255806003558060045580600555806006558060075550 +2e8d8a457543cf940ef631ca98fcfd11c5cb1119d2e6d6eda3efb2a8a1c5d674=6000600055 f1e3bd42875da1d50d5f6ee47b7c3a81cdfa546ce482edf6cd3e276d661e27f4=73095e7baea6a6c7c4c2dfeb977efac326af552d87ff00 -6c0bee772d21bb9572e13fba061d867af488ce4c4799703b5c1953648cc1cbd7=6000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa61157cf160005500 +4ded1eb002cb054874f2ea1996edd56bd3da577953433c9aaa702976cd608321=5a6016526001600a556000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa600035f1600b55600060015560006002556000600355600060045560006005556000600655600060075560006008555a6016510360175500 a6524cc4b8de915b5b279f9b2f6591f15af39ee9f677579cdbbebd9eeba36913=600060015500 +6c0bee772d21bb9572e13fba061d867af488ce4c4799703b5c1953648cc1cbd7=6000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa61157cf160005500 b6a870e429c801eacf3617f4a0c5705161fc4b18909b049f784cc616cd3d6001=6000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa611770f160005500 9a05bdf67390a39f5683805ac16680e40d9537fc8143500c3d1e60e863143690=6000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa61138df160005500 3e8a6be65fca78f831f0fc9d261d63e566d4ea6f580b763ed5ae3fce6f3562e0=6000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa600035f160005500 @@ -2127,6 +2007,11 @@ f138dcfed5bbdbd7e4b21866ccb59e0ee6f66d493dbc9f4445c64b313aeed11e=60aa60006000600 d5b367e8600704385458fb4001e9f55a8fa2f57d7f861f0f4bfc53162c24de37=60206000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f150600e80603c60003960006000f0503d6000550000fe6211223360005260206000f30000 c3aaa46b1bcad7e65b2f93c8d62b8ddf023c2217dae18d3542b31fa445897e9b=60206000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f150602060006000600065ffffffffffff730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f1503d60005500 ecd1d96f20e09e6de52af48896e1e955214fdfc84299aa74e6f22bc31818e538=60006000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f150600e80603c60003960006000f0503d6000550000fe6211223360005260206000f30000 +161997d4cd71eeac3a1229ed1334818012302b0e4fde1db26818bd6a499c7acb=6000356160a7600052806000f350 +708e124a9dd48d3f9fed7de053464e4a73b23a3b11270d7dd3ecd3078915663e=6000356160a7600052806000fd50 +8fc69ebe56dd2a6b658881e1287c49a7966486390dc49bea82ed4228f571c71b=6000356020356040358160005260206000602060006000875af1503d6000553060015500505050 +ca4a5d2e59e72586a296c5928c1ad18abd1d5ee9dcee43c3bd4c6c6472a23025=6000356020358060005260206000602060006000865af150307846455050 +293709612af3fad0c2119caac70779499e03a1e504e1a316b6e0161a77b9e34e=60043560243560443560006100ce565b6000607f60005382600152606060215360006022536052602353606060245360ff60255360606026536020602753606060285360206029536060602a536000602b536060602c536000602d53607f602e5381602f52605a604f5360f1605053606060515360206052536051605353606060545360006055536055605653603d605753606060585360016059536055605a536000605b53605c90505b92915050565b60006100bc838361000f565b60fe6001820353809150505b92915050565b8360f0811461013f576111f081146101575760f5811461016f576111f5811461018a5760f181146101a5576111f181146101c45760f281146101e4576111f281146102035760f48114610223576111f481146102405760fa811461025e576111fa811461027e5760006000fd610298565b610149838561000f565b91508160006000f050610298565b61016183856100b0565b91508160006000f050610298565b610179838561000f565b9150615a178260006000f550610298565b61019483856100b0565b9150615a178260006000f550610298565b8360005282602052602061010060406000600062ca11ed5af150610298565b8360005282602052602061010060406000600063bad0ca115af150610298565b8360005282602052602061010060406000600062ca11ed5af250610298565b8360005282602052602061010060406000600063bad0ca115af250610298565b836000528260205260206101006040600062ca11ed5af450610298565b836000528260205260206101006040600063bad0ca115af450610298565b83600052826020526020610100604060006557a700ca11ed5afa50610298565b836000528260205260206101006040600063bad0ca115afa505b503d60005560005160015550505050 bdf500c86f231800385106c4eab9f4a9e0ec938f514e501fc7d35bb7683fac51=602380601560003960006000f0503d6000550000fe62112233600052602060006020600060006004619000f1503d60005560206000f30000 b051a2695de61dc1f8fe6c50384ffabd135e0c645c1fccdee63eb37c18ad7741=36600060003760206103e8366000600060055af26001556103e8516002553d60035500 f8f5b19526c9d84bc95117b16831037cb97126b1444a88bb23ec93ceb035aba7=600780601d60003960006000f0506000600060003e60006000550000fe60016000550000 @@ -2135,10 +2020,10 @@ f8f5b19526c9d84bc95117b16831037cb97126b1444a88bb23ec93ceb035aba7=600780601d60003 758e92cde37c427e1b07b24d2ef29eedf1b4d7d751fdc6a810f72b7a0778c419=6000600060006000731000000000000000000000000000000000000002612710f4506020600060003e60005160005500 00c441f2b4e2a23fda7eef407948ba235b74a414dff979b1561064945069f5b8=3360005260206000f300 dd3bbb7ecc8bfd78bf710b1255cf3b301b0a756ab260ec6d876cc0307cd36e7e=60006000600060007310000000000000000000000000000000000000026000fa506020600060003e60005160005500 -8adbfbd72997442672335696caa60cf9b9b8e01e77de1376075c8d4e1c9a5717=3360005260206000fd00 cd446ca1ba0c4d0e1eb1ec088cc54e93e9612e3d4c9c338fe91af58937f70b8f=600060006000600073100000000000000000000000000000000000000261ea60fa506020600060003e60005160005500 -2ced4da970e939336a948595b4f5cce901ea7d5ee9d5d7ff7b7e36681b548386=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000f300 +8adbfbd72997442672335696caa60cf9b9b8e01e77de1376075c8d4e1c9a5717=3360005260206000fd00 105560c2675c8add352fd3988fb3b2102447185de01fda631f740ca38f5cbc6b=6000600060006000600073100000000000000000000000000000000000000261ea60f2506020600060003e60005160005500 +2ced4da970e939336a948595b4f5cce901ea7d5ee9d5d7ff7b7e36681b548386=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000f300 c9da6b2267bf1df2805231660fe98266cfe9d714998e507390e60330f3263f0d=600060006000600073100000000000000000000000000000000000000261ea60f4506020600060003e60005160005500 5060f04aaabe7f06a6359e3a1f732141d3dee099d8604a7d96bd47f04d142e2d=60006000600060006000730aabbccdd5c57f15886f9b263e2f6d2d6c7b5ec6640900000000f1506020600060003e60005160005500 bc41a1d08d89f9c286a585d00ab125c327a6af22694673d7fe8f7d8b40d7e990=6000600052596000526002806028600051396000516000f0506020600060003e60005160005500fe0000 @@ -2154,75 +2039,84 @@ aebfca6fd92ff5124492fde66977f3371368d49ab3030522363987f60716b3b6=6e1122334455667 16044d4782c7058a27965f030841bdf2f7d7af8af698d9811c78787d3998fce3=60006000600060006000731000000000000000000000000000000000000002620186a0f2503d60005500 b9ecfbbe4d474908c2dfe223c783da3c357fab53255433e2e9569314178d1d22=6000600060006000731000000000000000000000000000000000000002612710f4503d60005500 119b37c6021392a530ce658c96baacec7650f009d92f02efb9f433342abb2856=600060006000600073100000000000000000000000000000000000000261ea60fa503d60005500 -fe0af8e75cf2e035b8b23bfbed37332c3925a20a60bca0e51fb94cc4ccfc0e24=60206000600060006000731000000000000000000000000000000000000002620186a0f16002553d60005560005160015500 b9168b5e48b3ebd7406e0fa51ea2c0f865a13888ab65b6fd4788b9ae95b1923c=60ff60005260206000f300 +fe0af8e75cf2e035b8b23bfbed37332c3925a20a60bca0e51fb94cc4ccfc0e24=60206000600060006000731000000000000000000000000000000000000002620186a0f16002553d60005560005160015500 9ce7213533c5998b452a41c3b7f9ef6648024a541603480edffe4a7c3bbd90e7=6000600060006000600073bb00000000000000000000000000000000000000620186a0f1505b60011560345760016000556025565b00 5c16be70c40c5c693c182e60c812dc5d1bd6ea0859ded130c3ce3487aa0f48d1=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260066000f300 f35e49c73c0a888b6c0e443c097739497fafe4035143a02e35447272c4653ac6=6000600060006000600073100000000000000000000000000000000000000261ea60f2503d60005500 -185f20ff61caf8d7018cb183bbedf3679658fb8c5ed5af5adbeefbade8144956=3360005260146000f300 1b5310e67a245b79d0ab8131e41c822ee4e1ce46448d8b473dbcf074e339bff6=600060006000600073100000000000000000000000000000000000000261ea60f4503d60005500 +185f20ff61caf8d7018cb183bbedf3679658fb8c5ed5af5adbeefbade8144956=3360005260146000f300 9ce395ea9d8983ea96b855c7295a9fb0eb0765cf768bc7c8e6bfaf6570e82896=600060006000600061c3506001600af150600160015500 61ad6db59417ebd7b09a5c7831d035277b13ed9ccaf902dc554911285e0f7683=600060006000600061c350731f572e5295c57f15886f9b263e2f6d2d6c7b5ec66001f1503d60005500 4d421b7cf93e7f40f00c1550a5a230f35f398e061f5bfd4d5866a8b807da62c0=600e80601560003960006000f0503d6000550000fe6211223360005260206000f30000 3e8e081bbde4c7bceffb768abbaef57dffec021049d0b152ed1aa89a645184eb=3d60005500 840e4db4d3b170831b6679c863c2a54133deaa2ece07122ae5ef07f1634252f9=6000600060003e60005160005500 +1dad258daacb554e0790f9c58d727d5dc479ff318bbd0ce4e7b872a137dab38a=6000602435146100115760005061001f565b600980610391600039610100525b61ff006024351461003257600050610046565b6000600060006000600061ff005af1610100525b610200602435146100595760005061006d565b605060005360006001600001536002610100525b61030060243514610080576000506100a4565b60606000536000600160000153605660026000015360006002600001536004610100525b610400602435146100b7576000506100eb565b6060600053600160016000015360606002600001536001600360000153605760046000015360006005600001536006610100525b610500602435146100fe57600050610112565b60fe60005360006001600001536002610100525b60006024351460f1600435141661012b57600050610155565b604060006000600060006101005af1503d600055604060006000600060006101006000f1503d6001555b60006024351160f1600435141661016e5760005061019c565b604060006000600060006101005af1503d60005560406000600060006000602435620f00005a03f1503d6001555b60006024351460f260043514166101b5576000506101df565b604060006000600060006101005af2503d600055604060006000600060006101006000f2503d6001555b60006024351160f260043514166101f857600050610221565b604060006000600060006101005af1503d600055604060006000600060006024355af2503d6001555b60006024351460f4600435141661023a57600050610260565b60406000600060006101005af4503d60005560406000600060006101006000f4503d6001555b60006024351160f46004351416610279576000506102a0565b604060006000600060006101005af1503d60005560406000600060006024355af4503d6001555b60006024351460fa60043514166102b9576000506102df565b60406000600060006101005afa503d60005560406000600060006101006000fa503d6001555b60006024351160fa60043514166102f85760005061031f565b604060006000600060006101005af1503d60005560406000600060006024355afa503d6001555b60f06004351461033157600050610352565b60406000600060006101005afa503d6000556101005160006000f0503d6001555b60f56004351461036457600050610388565b60406000600060006101005afa503d6000556101005160006000615a17f5503d6001555b6160a760025500fe600160000360002000 +e100f08670c1c78b59351c33526f8d7eb4e4abeaace4bde8f8f9a65e826d905f=600260016000030460005260016000510160205260406000f300 +518779d7b59baf1ff9c3c45cff398e12ae2d88511da81ec16f9a0dd9e8b32c6d=600c600060006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f1506000516000556000600052600c60006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f4506000516001556000600052600c60006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40fa506000516002556000600052600c600060006000600073194f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f2506000516003556000600052600c600060006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f1506000516004556000600052600c60006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f4506000516005556000600052600c60006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40fa506000516006556000600052600c600060006000600073294f5374fce5edbc8e2a8697c15331677e6ebf0b62030d40f25060005160075500 +ff06284e0407bdc49c5eef8b55970f90a62e18cdf210a830c4f834f91a71f994=7f11223344556677889910111213141516171819202122232425262728293031326000527f333435363738394041424344454647484950515253545556575859606162636460205260406000f300 +a4cb6609f02e609855d0ae4469bc0c2dc008e0b6b77906b9622eb50e147b4a22=7f11223344556677889910111213141516171819202122232425262728293031326000527f333435363738394041424344454647484950515253545556575859606162636460205260406000fd00 +a803bfe42bdb99fe3090d66eefe6c6992f5677953c520ec7ece5b5a4b8b928db=6000357f1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201ff60005280600055806000f350 +9fb65906349b75182a0aea5e5020ca92c4bff64eba948b986bb4ba18caf322de=6000357f1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201ff60005280600055806000fd50 +0f73f356d63d54c487e160fe69035f674a815e71913d266052f8b5a35b4e2b64=600435602435604435606435836000526101006000602060006000855af182846101003e61c0de3b6020016000600061c0de3c36602001600060003738602001600060003961dead6000555050505050 4eef5052b492b54594df3d7ba37b5b619fc81a63981dbe3e5ded7115c51644f8=6001600054016000556000600060006000600073b0000000000000000000000000000000000000005af100 47513d8ba80f62468bedeb52e4a41afafa57013079eb37939861f95d5c98f578=6001600054016000556000600060006000600073a0000000000000000000000000000000000000005af100 995aee3e8c5b5615400ead8106a3309fb4e38b06f44753ca2b209aefe698aab5=60005460010160005500 -2cae8875430fe46523b61dc18a2fc87da9abeab97011c1ec7577fa7356ae0756=600160005401600055600060006000600073a0000000000000000000000000000000000000005af400 7f4605a1aad677a8fb1dd57110051118add90d619b6dc53bd301e1849d40eeee=600160005401600055600060006000600073b0000000000000000000000000000000000000005af400 +2cae8875430fe46523b61dc18a2fc87da9abeab97011c1ec7577fa7356ae0756=600160005401600055600060006000600073a0000000000000000000000000000000000000005af400 b0ad0eef9078a814b41980e9cd2dfeea6f102c1cdaa6aadb5fe563528cdd7254=6000546001016000556000600060006000600073c00000000000000000000000000000000000000061c350f160015500 1ec6f47a4fe34ebded91833b6aa3eface5f7c6f5bd6dbe8a4c413288ee2d3ac7=6000546001016000556000600060006000600073c00000000000000000000000000000000000000061c350f16001555a60025500 a35f8f16a1d016bdf12a2b6acce812fe1e5e8a77c0f4f22a387c645583422111=6000546001016000556000600060006000600073b000000000000000000000000000000000000000620249f0f16001556000600060006000600073d000000000000000000000000000000000000000620249f0f160025500 b729186ceaa5a67fd8098e83f30236febf44a9f5d91de570fe34bb3af857e73a=6008600255600060006000f050600c60035500 9dce4945c71d01792533bd9e5329578fc79e8445aeaec2f2ccf34b63a487e5c8=61223260005260206000fd00 b97fb21bf3656ee0f7c642b99c3650acda2cfcb26474a23e1fbaf07bab794939=60406000604060006103e873945304eb96065b2a98b57a48a06ae28d285a71b561c350f26000553d6001556020600060403e60405160025500 +53a1824fc1a4451a418c68bbf4a08b9e1814e872d34c49af967d79e2454f988f=3050600d80602460003960006000f0503d6000556020600060003e6000516001550000fe6211223360005260206000fd00 df2ae27db7df40d08a468158826304dacf484d12bca37d68e1e214ff8e526e12=600a60205260206020fd00 70598f4acaa69f4a950ab8fd0b0d08717e7c220f057cd2507389ee6c24965617=604060006040600073945304eb96065b2a98b57a48a06ae28d285a71b561c350f46000553d60015560206000603f3e603f5160025500 cc05c22789c7358145e0a5f77b240bf8e4ec982f93c5b6ae50984477a5b337dd=604060006040600073945304eb96065b2a98b57a48a06ae28d285a71b561c350fa60005500 af5d00491b061867822572fb3545c4061853a8d8e9c8a3ced43a51f5c34d0adf=60006000fd00 3464e9bde5c71c833cc6831cd82721320f00e40234f90372a592d80882be119a=6000600060006000600073b3305374fce5edbc8e2a8697c15331677e6ebf0b620186a0f1600055600e60025500 33d45503472dd1a4e113cc68e971b6caf3937fa02d770be80668055e68a5b527=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f4600055600e60025500 -319cd5ed40e8ff86432b4cf3316d74e2cbc0f6977b097135d447c3f4d064e448=6000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f1600455600e60055500 -89e9a89b21328e3aea83e007869a6a4c3ff1b98fe94c60b1b07977d6c2f8b147=6000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f1600055600e60025500 895860136351eed3de541eb3d09df83e8daa38b5fcc40c45269a6b4cab883ff8=600c60015560016000fd600d60035500 -7d1fdfa405f46c1e83d1ab1cd7b53f0a3cc0146c6c365c908d62690200d3cf54=600060006000600060006000356203f7a0f1600a5500 +89e9a89b21328e3aea83e007869a6a4c3ff1b98fe94c60b1b07977d6c2f8b147=6000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f1600055600e60025500 +319cd5ed40e8ff86432b4cf3316d74e2cbc0f6977b097135d447c3f4d064e448=6000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f1600455600e60055500 3b357612db25ba26854d2f37558c7a6a47f0a1dca4f46e16e5eeda523ff4e2e9=6000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f2600055600e60025500 +7d1fdfa405f46c1e83d1ab1cd7b53f0a3cc0146c6c365c908d62690200d3cf54=600060006000600060006000356203f7a0f1600a5500 14fbe20c970af8fc8c386203907c949991b93320df402bb9ed5185b88dc38a02=6e600160005560016000fd6011600155600052600f60116001f0600155600c60005500 8b1ce28462104780a7aa93982e97da1b6f6948d48b21e5bd48899717b0247f24=6000600060006000600060003561ea60f1600a5500 -20f7607c5fdd32c0f2095adc899402f5d758147244b93039be132d2d605f71cc=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073b3305374fce5edbc8e2a8697c15331677e6ebf0b620186a0f16000553d60025500 d1b9a99ff301b3984b9a681af8a9abf44430b7837f840fb2b81e1e30381c4c2d=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f150600060006000600060006000356203f7a0f1600a5500 -dc66b56cd9184d970249516b0e5524c708b2e30be4563d17a5dc9a55e86800be=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f26000553d60025500 -6d3eeb967abb524f7487139cbd322889a1497f39d61b3631b9ac2415e7300b9f=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f150600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f46000553d60025500 +237fb00cc56bddf56cfe500979f1ced0efab82c327f8cd902800a197e0873324=600c60015260406000f300 +20f7607c5fdd32c0f2095adc899402f5d758147244b93039be132d2d605f71cc=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073b3305374fce5edbc8e2a8697c15331677e6ebf0b620186a0f16000553d60025500 2fc56ae367a9085b4961e02cb1a78061d320ea2601b907afdf2875fd8f902174=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f16004553d60055500 +6d3eeb967abb524f7487139cbd322889a1497f39d61b3631b9ac2415e7300b9f=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f150600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f46000553d60025500 eea250b53d6627f5ac656c0f6a5fcdc007795364ba913641335a4fba72d16423=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f16000553d60025500 -237fb00cc56bddf56cfe500979f1ced0efab82c327f8cd902800a197e0873324=600c60015260406000f300 +dc66b56cd9184d970249516b0e5524c708b2e30be4563d17a5dc9a55e86800be=6000600060006000600073ffff5374fce5edbc8e2a8697c15331677e6ebf0b6000f1506000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f26000553d60025500 c80af6033aafda8dab0312529df7ac0e6ce3ee9e68664aa1f3d8714814f4ec3a=600d80601560003960006000f0503d6000550000fe6211223360005260206000fd00 -04e48245db9a3c3476fed2e5d68e0db8f8492e5e5890e0624d72ea2aa2197762=600c60035560016000fd00 -ae83baa314f8d08ef26978bb651f062053846078ae2bea5838418e5a1842b23c=600c60025560016000fd00 +ee8b9e96deaca789fef2e186e903ab4eca54f3779f9fcaa96dd9dd4a20eb34f0=6000600060006000600073b00000000000000000000000000000000000000061c350f1600a55600060006000600073c00000000000000000000000000000000000000061c350f4600b556000600060006000600073d00000000000000000000000000000000000000061c350f2600c55600c600455600c60055500 +47a14c35cc677428f8a0ecd275553c312b4a296ce0f29475f5e0797a7d8fe2bf=600c60015560016000fd00 8cd7a6423ab8ec8845afd56fbcdcc2719343ae93b044567b2874c9e6918bbf37=6000600060006000600073b00000000000000000000000000000000000000061c350f1600a556000600060006000600073c00000000000000000000000000000000000000061c350f1600b556000600060006000600073d00000000000000000000000000000000000000061c350f1600c55600c600455600c60055500 2698e2391cb7be2d6df86ba0062ad67d31b592d61362d8a5ac6107823316a283=6000600060006000346000356203f7a0f100 bb34e89b4f88309b086ec2581cd2eecc885fb51307e8543b002ce411c11d8594=600060006000600073b00000000000000000000000000000000000000061c350f4600a55600060006000600073c00000000000000000000000000000000000000061c350f4600b55600060006000600073d00000000000000000000000000000000000000061c350f4600c55600c600455600c60055500 +ae83baa314f8d08ef26978bb651f062053846078ae2bea5838418e5a1842b23c=600c60025560016000fd00 +04e48245db9a3c3476fed2e5d68e0db8f8492e5e5890e0624d72ea2aa2197762=600c60035560016000fd00 76e98a46d06ac4c527b7911bf149cc00716d8f28c9020bd2558a0cec9db9171f=6000600060006000600073b00000000000000000000000000000000000000061c350f2600a556000600060006000600073c00000000000000000000000000000000000000061c350f2600b556000600060006000600073d00000000000000000000000000000000000000061c350f2600c55600c600455600c60055500 -ee8b9e96deaca789fef2e186e903ab4eca54f3779f9fcaa96dd9dd4a20eb34f0=6000600060006000600073b00000000000000000000000000000000000000061c350f1600a55600060006000600073c00000000000000000000000000000000000000061c350f4600b556000600060006000600073d00000000000000000000000000000000000000061c350f2600c55600c600455600c60055500 -47a14c35cc677428f8a0ecd275553c312b4a296ce0f29475f5e0797a7d8fe2bf=600c60015560016000fd00 -459bee294ee0354c254d9b1732de0e598a4c560582d2773a239cd0f3fc66cacc=6c726576657274656420646174616000556d726576657274206d65737361676560005260006000fd00 +05b81dc0e5b0bd4187605683d6395f4d82d71703093e70dbdd3bc0fe0533710f=6c726576657274656420646174616000556d726576657274206d6573736167656000526e0fffffffffffffffffffffffffffff6000fd00 7181d3ffeaa870b0caf01a52a66ed7cd21ba2ee2b2045c33b011986fdd31ea5c=60206000600060006000600035620249f0f160015560005160025500 e2e3bbd0bda8f67f70369cb7206b24e0496d947130a64ca55e9130999e762309=6c726576657274656420646174616000556d726576657274206d6573736167656000526000610100fd00 -dd3283c605d58dbe21d0a0f2ab884dda1c6e149eaff1840a77e1e12d06103b53=6c726576657274656420646174616000556d726576657274206d65737361676560005260006001fd00 d7257879609c29a12ae74b59a3fde006207a36328ff7f4fd2717eeba469dee1a=6c726576657274656420646174616000556d726576657274206d65737361676560005260206000fd00 +dd3283c605d58dbe21d0a0f2ab884dda1c6e149eaff1840a77e1e12d06103b53=6c726576657274656420646174616000556d726576657274206d65737361676560005260006001fd00 558e0faf375d92de9928c588cbcc3df3292a09b6dd0378a8112952bbe580bbe2=6c726576657274656420646174616000556d726576657274206d65737361676560005260006e0ffffffffffffffffffffffffffffffd00 -05b81dc0e5b0bd4187605683d6395f4d82d71703093e70dbdd3bc0fe0533710f=6c726576657274656420646174616000556d726576657274206d6573736167656000526e0fffffffffffffffffffffffffffff6000fd00 +459bee294ee0354c254d9b1732de0e598a4c560582d2773a239cd0f3fc66cacc=6c726576657274656420646174616000556d726576657274206d65737361676560005260006000fd00 +e5dd5859cf6cdb87486d7e024f31392ce9af7d4f24e935880b6a135151acac9a=60006000600060006000365af200 +e4590715e0237590775cab8ca93ac7d8497f5441f19a05e3e9e38a3a5af9fcba=6000600060006000365af400 +6b19b36fcd8315974e4f487b2fe71f3e75cfc690d5721b280c6f483d5fc07d78=60006000602035600060006000355af200 be94973c2c562d44b647c3bf84e2475f1ef7d0d19cd7f88973637552e788cb2b=60006000600060006000365af100 29d48283cedda1215773a86d298557f0f069d6265fd64e4171610c655a6614cb=6000600060006000365afa00 -6b19b36fcd8315974e4f487b2fe71f3e75cfc690d5721b280c6f483d5fc07d78=60006000602035600060006000355af200 -e4590715e0237590775cab8ca93ac7d8497f5441f19a05e3e9e38a3a5af9fcba=6000600060006000365af400 -e5dd5859cf6cdb87486d7e024f31392ce9af7d4f24e935880b6a135151acac9a=60006000600060006000365af200 -df05ce605786cf1f172027621ec602aa57b0b59011a8e363d786553b38845555=6000600060006000600161c350f4506000600060006000600261c350f4506000600060006000600361c350f4506000600060006000600461c350f4506000600060006000600561c350f4506000600060006000600661c350f4506000600060006000600761c350f4506000600060006000600861c350f4505a6001555a6002555a60035500 -02fe24861294db45cf790d2433acdf09424d0063d527734767f7ececdcce2095=600060006000600060006000355af200 -de7f48a9698a7a949a5cba3dbcc46058a43402095d34a5fa5db5d6a2cd6c5459=60006000600060006000600161c350f15060006000600060006000600261c350f15060006000600060006000600361c350f15060006000600060006000600461c350f15060006000600060006000600561c350f15060006000600060006000600661c350f15060006000600060006000600761c350f15060006000600060006000600861c350f1505a6001555a6002555a60035500 e9a282e75cfff1a6ac9e90ceedd6af19f59d0424430b266601a5a9fda6673736=6000600060006000600161c350fa506000600060006000600261c350fa506000600060006000600361c350fa506000600060006000600461c350fa506000600060006000600561c350fa506000600060006000600661c350fa506000600060006000600761c350fa506000600060006000600861c350fa505a6001555a6002555a60035500 +02fe24861294db45cf790d2433acdf09424d0063d527734767f7ececdcce2095=600060006000600060006000355af200 +df05ce605786cf1f172027621ec602aa57b0b59011a8e363d786553b38845555=6000600060006000600161c350f4506000600060006000600261c350f4506000600060006000600361c350f4506000600060006000600461c350f4506000600060006000600561c350f4506000600060006000600661c350f4506000600060006000600761c350f4506000600060006000600861c350f4505a6001555a6002555a60035500 2d6381d4b64e7fb761a5749f70108e4a6bd5fdfedbc665a2b63dcb5a1e419d8a=60006000600060006000600161c350f25060006000600060006000600261c350f25060006000600060006000600361c350f25060006000600060006000600461c350f25060006000600060006000600561c350f25060006000600060006000600661c350f25060006000600060006000600761c350f25060006000600060006000600861c350f2505a6001555a6002555a60035500 +de7f48a9698a7a949a5cba3dbcc46058a43402095d34a5fa5db5d6a2cd6c5459=60006000600060006000600161c350f15060006000600060006000600261c350f15060006000600060006000600361c350f15060006000600060006000600461c350f15060006000600060006000600561c350f15060006000600060006000600661c350f15060006000600060006000600761c350f15060006000600060006000600861c350f1505a6001555a6002555a60035500 ee12ccf48321392c3161569794e59e70f7be0a94df08c8ad4745a1c22e177e45=60206000602060006000737db299e0885c85039f56fa504a13dd8ce8a56aa761c350f1600055600c60015500 e10e9441043a020bebab4dad741bbff857fd56514ba85587ced83a1cbbd8881f=60206000602060006000737db299e0885c85039f56fa504a13dd8ce8a56aa761c350f1600055600c600155600c60025500 c5c83e7953c7f26673d31c14507cc529cfeeb8cdc96d2cc7e770a7c22c6b1ea5=602060006000f0600055600c60015500 @@ -2230,59 +2124,158 @@ c5c83e7953c7f26673d31c14507cc529cfeeb8cdc96d2cc7e770a7c22c6b1ea5=602060006000f06 a918da4c499f558eae39cf8cb1054c391a9b036b7dcad9cf8a5bbcff148b7866=602060006000f0600055600c60015500 b2fd212493f89d3b09afd9c45eeabdae28600767536d39cc971048a8f451a456=600060006000600060007310000000000000000000000000000000000000006201fbd0f16000556000600060006000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0f160015500 5d8a411ccd418a3581405e3635df63eaa615b4018ed5e240a967ae5864ee9cbb=600060006000600060007310000000000000000000000000000000000000006201fbd0f1600255622fffff60002000 -739204052436f7bd0bd121ebc5bcf6270ffd6b7c5e533f1688fd7f2d59ab3351=6000600060006000600073e94f5374fce5edbc8e2a8697c15331677e6ebf0b620186a0f1600255622fffff60002000 64820d3e7cc7fc1bea5d63ae7615070a7646ae1a0daf9a88650ff0a8635a1912=731000000000000000000000000000000000000000ff00 36b0a23503550cb1130badb6429992339e51df072f544b616c691ec951df4a49=6000600060006000600073d94f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0f16000556000600060006000600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0f160015500 +739204052436f7bd0bd121ebc5bcf6270ffd6b7c5e533f1688fd7f2d59ab3351=6000600060006000600073e94f5374fce5edbc8e2a8697c15331677e6ebf0b620186a0f1600255622fffff60002000 076fe75197c119cb43e28a5d7a04d7125e0213a96268b62cd1f857c6f493c69e=6000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b617530f1600055600160025500 03cf95fee543c360abf34345f9e03afb9142224d593f7b2fbe8c2987a2514100=60006000600060006000731000000000000000000000000000000000000000617530f160015500 -e733e74ec01757128edee2c68b71b65c8a741c863e12d20fc4956575ee3575cb=6001600155600060015560016002556000600255600160035560006003556001600455600060045560016005556000600555600160065560006006556001600755600060075560016008556000600855600160095560006009556001600a556000600a556001600b556000600b556001600c556000600c556001600d556000600d556001600e556000600e556001600f556000600f5560016010556000601055600160015500 -36f9db2473727c60d9e532538f556fe6bededa1527ed06644f1b093c8d37557c=600060015500 -58d1fd0c2c63963da3187c539fe3f98b6f3c3e3cccbe4c6c3e4bfdf8cb64665f=6000600155600060015500 -f9ad99513f958bb89a4e3539068e96756ccebb8915f98a95a364f71051140b42=6000600155600160015500 -a8718caa8a93a18ef0a036d3ac0fdf507317c11109801f7345592a42dd3fe4e5=600160015500 +62516506325d7cd9a9c5ed8d0c534e9dde66627892fcb141a0a58814482c4d9e=60106000fd00 +52aadc0ad8118342fb956b517e52d1e9af1705ebde4526e70a7e7803d994b5f7=5b6001156013576301000000600020506000565b00 +7ff408e57e6ca4efed1ae0920cf2e2d4d01b9b11790d80fbb03e6a706145260e=600160000360002000 +05f086dcbd850473bd11208c9e821dbf8b9ebe4095edaf3aee8f6b9dd4f6b2ba=6000602435146100115760005061003b565b5a600052600060006000600060006004356175305a03f1505a602052602a60205160005103036000555b60016024351461004d57600050610075565b5a60005260006000600060006004356175305a03f4505a602052602760205160005103036000555b600260243514610087576000506100af565b5a60005260006000600060006004356175305a03fa505a602052602760205160005103036000555b6003602435146100c1576000506100eb565b5a600052600060006000600060006004356175305a03f1505a602052602a60205160005103036000555b63040000006000541161010057600054610105565b62ffffff5b60005500 +0a4b8458a53bca2e23b7be94690a4436eb6e4081d48378cf263177c4e66da62f=6160a760025500 +10391197b6d3cd7f22c044e4a904c1f7136daa5ae42fa8590879ae0d8ad4c795=610100600155600060006000600061dead6175305a03f45060106000fd00 +a34b7fbfec51c8541a6fb948321c07845a592acba08b13c14e8f8af22fedad76=610101600155600060006000600061dead6175305a03f4505b600115602b576301000000600020506018565b00 +d86c106de10d7cd27f75e873cc9c1c3fb020b5e3680122c421619a7efe7ec1d0=610102600155600060006000600061dead6175305a03f450600160000360002000 +b2d81f953c790a7e4b483d54733f2596be5c1ea4ee0f35263509fef8001bc26b=6160a76000556000600060006000600435610100015af400 +e733e74ec01757128edee2c68b71b65c8a741c863e12d20fc4956575ee3575cb=6001600155600060015560016002556000600255600160035560006003556001600455600060045560016005556000600555600160065560006006556001600755600060075560016008556000600855600160095560006009556001600a556000600a556001600b556000600b556001600c556000600c556001600d556000600d556001600e556000600e556001600f556000600f5560016010556000601055600160015500 +b4c5e7abf2c1e7d3ab977f12b44b93ae99ea6b4ce5c670a962d342aa6028203c=6000600155600160015500 +438fe345117cd7ad596753bcf57091f81c32dfca164e1b45269b97cf9c09e879=6000600b80601360003960006000f5500000fe6000600155600160015500 +3bf29bf3eb0c4135fa025457b168546cb4980523dd9f0aa748f7d95c092e034b=6000600b80601860003960006000f55060006000fd0000fe6000600155600160015500 +8fecce8e335fb1fb2a6807744153cbeee93c36edfeb191e66e4c005beda348aa=6000600b80603860003960006000f5506000600060006000600073dea000000000000000000000000000000000000062030d40f1500000fe6000600155600160015500 +3f0007b88f06463a813b03c55b07ee91057e2bc54fc36d4dac83a7a9e1a7afd7=611000600d600060005a915061beef6000555a9050828183030384556001840193505a915063deadbeef6000555a9050828183030384556001840193505a915060006000555a9050828183030384556001840193505a915060006000555a9050828183030384556001840193505a91506112346000555a9050828183030384556001840193505a915060006001555a9050828183030384556001840193505a91506160a76002555a9050828183030384556001840193505a915060006003555a9050828183030384556001840193505a91506160a76003555a905082818303038455600184019350600060005560006001556000600255600060035550505050 +36f9db2473727c60d9e532538f556fe6bededa1527ed06644f1b093c8d37557c=600060015500 +71891782a36768b68f09d49991e9e9b72f8555e2be3ce293dd936cb9bc1b33da=6000600060006000600073b000000000000000000000000000000000000000620493e0f1506000600060006000600073dea0000000000000000000000000000000000000620927c0f100 +e099d68aa4f2daf6478c3bc0b7548c9734e931aadbb11b30f05e237e99d75350=6000600060006000600073b000000000000000000000000000000000000000620493e0f2506000600060006000600073dea0000000000000000000000000000000000000620927c0f100 +9f6d79f8482e993b5f25658c889c2d4430fd144199b705155d6498c170a3d052=600060006000600073b000000000000000000000000000000000000000620493e0f4506000600060006000600073dea0000000000000000000000000000000000000620927c0f100 +1746fa5b8f53d54e021c7806e3ae5e395815d7fb52f8b33663236036207faf6f=600060006000600073c000000000000000000000000000000000000000620493e0fa506000600060006000600073dea0000000000000000000000000000000000000620927c0f100 +f7ecb300fa680c5646609e246335b9590eae3984cc8e9d877a6d1a96dd78d06f=6000600b80603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe6000600055600160015500 +25545ad8736b4da3db816ca115b8fdf0dcd889666ce9d209775c077fa4d4120e=6000600060006000600073b000000000000000000000000000000000000000620493e0f1506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd00 +55a9d8460b24e3d0227c9422a735e4870105a67dd2958c143572e2d040019ae1=6000600060006000600073b000000000000000000000000000000000000000620493e0f2506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd00 +6deee4808eec3bae38b305056e5b4f469806f187c2c9b7e56199dfa9bdfb4ab7=600060006000600073b000000000000000000000000000000000000000620493e0f4506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd00 +2b4378966c91379f6ee0b221c36b8f7c299bb6d00ca8e45cb67a981f2b9f546d=600060006000600073c000000000000000000000000000000000000000620493e0fa506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd00 +8e8cced5a66880190481484ebc888f016abf26edb6b63952fd56ad9902fc8abf=6000600b80603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe6000600055600160015500 +58d1fd0c2c63963da3187c539fe3f98b6f3c3e3cccbe4c6c3e4bfdf8cb64665f=6000600155600060015500 +41e9c2b79ea10471c568869d4e417496b4d7da183b67a40d98ccfcb485724f49=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60006000556000600055600160015500 +d5ea3c39ab410861d60d2b43a169701ee20db5eddc5d2ca0f18455f44aaa2e5a=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60006000556000600055600160015500 +f9ad99513f958bb89a4e3539068e96756ccebb8915f98a95a364f71051140b42=6000600155600160015500 +29a0de90a0b1555166a33a0119fb0608f211fca9e1f8a5ff8b4275ea3a1e9b41=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60006000556001600055600160015500 +049384d05388927ad43efec6f0e1094d6756dae21882f25ca3cee69993b00539=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60006000556001600055600160015500 +a8718caa8a93a18ef0a036d3ac0fdf507317c11109801f7345592a42dd3fe4e5=600160015500 868dc1fbee1616f28d5e5422704ada4f4b530ba9d43985c879da4dc245de25f3=6001600155600060015500 +51c9574629bcf5d57a6d1ae22edbe947c373fae8443a36d28ac67924fd179223=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60016000556000600055600160015500 +8b1c576fd5dde376e5dd2c272ed032832da9e421b26b58ecc428d04b24ea8842=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60016000556000600055600160015500 f322975b3a57218794484c866d2dad48fc15dc680f638868ce645f8c3703c0b4=60016001556000600155600160015500 +f0deaf54708e026c126bd71b87345c00a82f1db41a00cd1a155e79ed86f28826=6000601a80603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe6000600055600160005560006000556001600055600160015500 +7f94638cc54702bf94933a6d1ee2f1ffbacb385733403aaa3c6b1134bbdbfdb9=6000601a80603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe6000600055600160005560006000556001600055600160015500 8a9528fb8b430b574d7fe207e4d4c11236e172084cd84d6455fa84053efa594f=6001600155600160015500 +782cc82a9fcab1d050728fbf61ed4f67aa3795eba9ab5ec32b153d9b69df1c02=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60016000556001600055600160015500 +bbdc0c21f43d7cc053dbfa83471f6eb5f20a8e8bd472a3455b830ee3dad4cd74=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60016000556001600055600160015500 8a1ff46eacb865b905d869453c6efa6690421ccad74f76892455a84945fedf70=6002600155600160015500 +0147f11f9e025d0345e7299b37b2dd707acec8ad89932fbf478ad10eec37cf07=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60026000556001600055600160015500 +5b8500988fe75e09a7750264018eb01eda3e06312d7eee426f53944ea14a9969=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60026000556001600055600160015500 +55f860845bb4e5a266cf4be224ebe6b2ac36b720657080be02aa64be357ca0d4=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560006000556000600055600160015500 +5e37109701f2b28987aa472047648319f4c383bb996bde2678b8dd90709fdfcf=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560006000556000600055600160015500 +717d575e4c7e9d1a93058587fbf452ba70f94612d632cc8c59606a54b63fc149=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560006000556001600055600160015500 +3e4bb760c8f9af445c0136087aed8cb2505c0f03190d676afc3dd8691f2639cb=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560006000556001600055600160015500 8b5266dac7aa83432e7a4071275ac3207e5ef504ee5ca046f1cb586d1ff71a16=60006001556001600155600060015500 +ee080d677112344e86df581a9c0000bf1345d63e141dd3001a133cb4bca6c820=6000601a80603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe6001600055600060005560016000556000600055600160015500 +fb683cf50f9889a6f3bf08aaa86d3a56744cf65e705b0ca5429bbaf749d5581d=6000601a80603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe6001600055600060005560016000556000600055600160015500 +9bbfcdc8698cb4033516bf18944810b6ef0b246029edaa95e4204adc9b786ad2=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600260005560006000556001600055600160015500 +55eeb5d356b4d29875392900da428340d11a6924e38b75dbe8e90899433a01d2=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600260005560006000556001600055600160015500 +2570c15ef683a5de7fc0f6be4b25d3b1a0e06af713f7cfeea6fff59f7853ebec=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560016000556000600055600160015500 +5107cef9dddfac3d9e3e45b5c9b365c4415c28a8e0472569ef7128e58ba1f680=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560016000556000600055600160015500 +86c686872a48a822b3175ebc1d99ba3510440ecd2ae25e60234ded212856d7cb=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560016000556001600055600160015500 +b3a8f1d1466d1f3fd7d30047dc29fba75a38056e205e500d9e9f6e193d52e656=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560016000556001600055600160015500 +e1fa97c83a54f7f4e0aabb2042a916f2fe4033367580da4a417a21cae4944780=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600260005560026000556001600055600160015500 +304d5614aa002d9edbae78d6be955868f32d371d6476a45dc7a6fdd0a2e36da7=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600260005560026000556001600055600160015500 2fd877d753d9cb2ee56551103e1ca4ec5cd4da266467c29b61e4587c76ed784d=600260015500 +447a1225165db03d156c0de00234f4e929ff00982d0fd7ce6cf9698950e645e9=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60016000556002600055600160015500 +0999679fee9c935b7bc602007c765c601ece025c88922e0ab503b4979cf741b5=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60016000556002600055600160015500 cdb31fda621fa0b661ae7dabad5e7f3d8cafd4b3217486c63275868cd3473c52=6002600155600060015500 +c66e1669b097202bdf2367fa4a09c5ccede3a735449427cfda2210bd06c854d5=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560026000556000600055600160015500 +12ea25982a4c21ade8cc1543d8d3fcdfe9b641c24446658bdbdcbbad8820f74e=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560026000556000600055600160015500 +ae838bf60cbee93b47a9cdac70c9c2a62962c9fe975a68d0c07fe244fc8c9558=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560026000556001600055600160015500 +38cb8e8bad41f6c090d9e5746cf6173181b0aa11df92f99dc0aa0db729c8583f=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560026000556001600055600160015500 +86604fd79d1febe3ea6b3a5e5e3c5afe4d72e3fb144d5865033b6d3f4cb9a57a=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600260005560016000556001600055600160015500 +ffc7be0afa74c4bcd22e2fb76fac391eac9534dc12856b760f1911250ecf20be=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600260005560016000556001600055600160015500 a201d01fd0d69ac374f6b7162ff799ce1c8e5108d0133fffe574ab0d669a0360=6002600155600360015500 +3af869d3aa41bf3132ec73926890abb26811807c9e27853fd42c258fceb121c4=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560026000556003600055600160015500 +80bd7d9f5068f3812d8a63a4ed6e9a3851fa3b7ef361b651ddb8aef1b3d580f3=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560026000556003600055600160015500 50fc29c1ca9eea0a7c9412570ddd8cfdd270fa180745158ec2a0619a33e6214b=60006001556001600155600160005500 -1522ad3b0977279901f764d101aa489b07fa85f6f37cee639806418348fcb76c=4760215500 +f757fae5f4eb63182517dbb919fa741b10dadf37687c7f52d42c8ac981bbbe0f=6000600060006000600073bea0000000000000000000000000000000000000620186a0f100 +a9ab7f2212c8e46134059b4c7b825ba002f67fc95b931863bd93dcf8d947d722=6000602580601360003960006000f5500000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f100 +4b6b2913c5edfc9cf7aa4dfd41047495409ad32ce3aeb84c5375f8ea6055bfbc=6000602580601860003960006000f55060006000fd0000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f100 +d075320df7bd25b27cc3687b005c8779e3f5ad8cec0acbb6ebd91970c5fa2fc0=6000602580603860003960006000f5506000600060006000600073dea000000000000000000000000000000000000062030d40f1500000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f100 +de5ccc55fa69e6da7a061c64dbaa7810dcb8861feea2eae5e3c77a4f40ad5ec4=6000600060006000600073bea0000000000000000000000000000000000000620186a0f200 +02d0e9785e8763983715149b65b21a031d3ebde207581f12d7d09b0d10946394=6000602580601360003960006000f5500000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f200 +19225772c6a134782d03ad56908709d172fb07c5ee35e71a6b70f2e533ab558b=6000602580601860003960006000f55060006000fd0000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f200 +d3ac721d201b205ef46f4e6dd82f9231ac71d39b0a19bbe18c5dde5ddc9de7cd=6000602580603860003960006000f5506000600060006000600073dea000000000000000000000000000000000000062030d40f1500000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f200 +f92e3935274932032c772dbbcbc224203869b4b2efc171e5ec5a23579d8cd846=600060006000600073bea0000000000000000000000000000000000000620186a0f400 +905a47cdd17e3fbcb986f8c5f1f764645743641462c178a5a116c12c60916974=6000602380601360003960006000f5500000fe600060006000600073bea0000000000000000000000000000000000000620186a0f400 +10472629d0f6168352db4aa653c15990c97621e6522c403bab029f577d06d9b8=6000602380601860003960006000f55060006000fd0000fe600060006000600073bea0000000000000000000000000000000000000620186a0f400 +8d917969ad8373792c4cf0d64acc12a5ab59494433a2fd384830ce73f34f1411=6000602380603860003960006000f5506000600060006000600073dea000000000000000000000000000000000000062030d40f1500000fe600060006000600073bea0000000000000000000000000000000000000620186a0f400 +086087e15b5c513c69f51269d3206f488eeb45eade598ed5790cc6a8892a7db3=600060006000600073bea0000000000000000000000000000000000000620186a0fa00 +63462454d8c043fa2d283b69e632789b28c1a91a3f74a9be9ad332a6fb24f395=6000602380601360003960006000f5500000fe600060006000600073bea0000000000000000000000000000000000000620186a0fa00 +6039a8923c6f7c28763f3221f81b54030bcfc70637d4205c581d929c60f3ed35=6000602380601860003960006000f55060006000fd0000fe600060006000600073bea0000000000000000000000000000000000000620186a0fa00 +472679aaf2fd729d45bdf351f55e1f1efb1698d35a93444ea2725f760d1cb5e8=6000602380603860003960006000f5506000600060006000600073dea000000000000000000000000000000000000062030d40f1500000fe600060006000600073bea0000000000000000000000000000000000000620186a0fa00 +6e7b859102a29fa992c7eda66444f62a8511cc1ab19d4ea736765c792049cdcc=6000600060006000600073b000000000000000000000000000000000000000610901f115604b576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 +b2e74ed55d92f82a05f2113bf763854ae51caf3afcb618d6469feb1223db0a46=6000600060006000600073b000000000000000000000000000000000000000610902f115604b576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 +6c90cf457538e29694799179f698cc875b1ea95c297387e478de97c775674b1d=6000600060006000600073b000000000000000000000000000000000000000610903f115604b576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 +e798273f90ee37816ec2050556e4ccb681c0a17dbe4ff09abf7ba18e33f8459b=60016001556000600060006000600073b000000000000000000000000000000000000000610901f2156050576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 +3db68f13d49b2350284bd754957b34f1105923ef81af8476014ccdb37b13b09d=60016001556000600060006000600073b000000000000000000000000000000000000000610902f2156050576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 +885b5bce0ccc44b9ef0c3b25fdc8d0c36fd298c73bb3c630c76e3558d7a8bfb2=60016001556000600060006000600073b000000000000000000000000000000000000000610903f2156050576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 +148d0d09c7fe4dda5404ea7f5c71746264665aa81789b1b130eb27b35140e53a=6001600155600060006000600073b000000000000000000000000000000000000000610901f415604e576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 +875cbaee3f9ca78b36415c70403eafcd88c66543127982f5f89b3b06123963f9=6001600155600060006000600073b000000000000000000000000000000000000000610902f415604e576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 +2deb9469ef0902c49112f3d39d76c543221f25edf34221b99bf612720ce063ef=6001600155600060006000600073b000000000000000000000000000000000000000610903f415604e576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 +8bbed1d29403ad31bc446e9eca24e6c2fedb931f1bd387377e80b179e966ffa6=476000526000516040526021603ff3 +eb957dab28ae072ae7dcc6ed70eae55227971d7f99851ccc1be18704448a5361=4760005260206000f3 +8d95f8713c7ef660d149c2330a4ea05923319e1fad7a6acbc1804cb953f0dfbe=60043560016001602061c0de3b63c0dec0de3b6160a7600052856000811461015c5760f181146101655760f2811461017b5760f481146101915760fa81146101a55761f1f181146101b95761f2f181146101d15761f4f181146101e95761faf181146101ff5761f1f281146102155761f2f2811461022d5761f4f281146102455761faf2811461025b5761f1f481146102715761f2f481146102895761f4f481146102a15761faf481146102b75761f1fa81146102cd5761f2fa81146102e55761f4fa81146102fd5761fafa81146103135760fd81146103295760fe81146103645760ff81146103a15760f081146103dd5760f581146104005761f0f181146104265761f5f181146104525761f0f281146104815761f5f281146104a65761f0f481146104ce5761f5f481146104f15761f0fa81146105175761f5fa8114610541576460baccfa57811461056e5765bad0bad0bad0600052610589565b47600052610589565b6020600060006000600061ca115af19550610589565b6020600060006000600061ca115af29550610589565b602060006000600061ca115af49550610589565b602060006000600061ca115afa9550610589565b6020600060006000600063ca1100f15af19550610589565b6020600060006000600063ca1100f15af29550610589565b602060006000600063ca1100f15af49550610589565b602060006000600063ca1100f15afa9550610589565b6020600060006000600063ca1100f25af19550610589565b6020600060006000600063ca1100f25af29550610589565b602060006000600063ca1100f25af49550610589565b602060006000600063ca1100f25afa9550610589565b6020600060006000600063ca1100f45af19550610589565b6020600060006000600063ca1100f45af29550610589565b602060006000600063ca1100f45af49550610589565b602060006000600063ca1100f45afa9550610589565b6020600060006000600063ca1100fa5af19550610589565b6020600060006000600063ca1100fa5af29550610589565b602060006000600063ca1100fa5af49550610589565b602060006000600063ca1100fa5afa9550610589565b47600052600051600055600060006000600060006260bacc5af1504760005260005160005414151561035f57640badbadbad6000525b610589565b4760005260005160005560006000600060006000620600066161a8f1504760005260005160005414151561039c57640badbadbad6000525b610589565b476000526000516000556000600060006000600063deaddead5af150476000526000516000541415156103d857640badbadbad6000525b610589565b8260008561c0de3c8284670de0b6b3a7640000f09450602060016000873c610589565b8260008561c0de3c615a178385670de0b6b3a7640000f59450602060016000873c610589565b8160008563c0dec0de3c8184670de0b6b3a7640000f0945060206000600060006000895af19550610589565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f5945060206000600060006000895af19550610589565b8160008563c0dec0de3c81846000f0945060206000600060006000895af29550610589565b8160008563c0dec0de3c615a1782856000f5945060206000600060006000895af29550610589565b8160008563c0dec0de3c81846000f094506020600060006000885af49550610589565b8160008563c0dec0de3c615a1782856000f594506020600060006000885af49550610589565b8160008563c0dec0de3c8184670de0b6b3a7640000f094506020600060006000885afa9550610589565b8160008563c0dec0de3c615a178285670de0b6b3a7640000f594506020600060006000885afa9550610589565b6103ff600052602060006020600060006460baccfa575af195505b508415156105975760206000fd5b8315156105a45760206000fd5b600051600055505050505050 +e072ca4e44f39e2861bf2dd3848ae1d57d606c88ab8fb7c557287f611fce8b15=4760005260206000f3 +d230b310957a07eb653cf0f74a2f0b12b2ce777c388d2e7429a2f6f76863ee4c=47600052600051600055fe +b0bbc0608478259d03d5b37781443defa85f60926523f33ac8621c634a3f8d8a=4760005260005160005560206000fd +dddc4cdd0ce51386ddc68be5f97ae1c4f9b0be4cf052c6024934cfae9fb271fc=60003560008114156014574760005260206000f35b60018103600052602060006020600060006460baccfa575af1151560385760206000fd5b60206000f350 84f7e621ac63ff99a09b602712f898bc3267717a9a0cf5d3e0814ef96e5dad21=3031471460015500 ec8a200e05896c520c791fd009255daec79d60e47a4bece6d62c3881d8424812=4760015500 86ee8015bb2d147fad87d3214308454eb4ce9a5fec625543e74bfe62d82a3289=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001d60005500 8b970febdf237af4319d966b8cc4879488b1ef366570668199a8b57a81181798=60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1d60005500 +dfbd09658814232694ba5dfb37d2fbb53f3be0c71ac1b5887e13b0680f394be4=60ff60005260006000602002612774015260016001602002612774015260026002602002612774015260056003602002612774015260fe6004602002612774015260ff6005602002612774015261010060066020026127740152610101600760200261277401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600860200261277401527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe600960200261277401527f8000000000000000000000000000000000000000000000000000000000000000600a60200261277401527fa000000000000000000000000000000000000000000000000000000000000000600b60200261277401527f5555555555555555555555555555555555555555555555555555555555555555600c60200261277401527faaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600d602002612774015260006000602002614e84015260016001602002614e84015260026002602002614e84015260056003602002612774015260fe6004602002614e84015260ff6005602002614e8401526101006006602002614e8401526101016007602002614e8401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6008602002614e8401527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6009602002614e8401527f8000000000000000000000000000000000000000000000000000000000000000600a602002614e8401527fa000000000000000000000000000000000000000000000000000000000000000600b602002614e8401527f5555555555555555555555555555555555555555555555555555555555555555600c602002614e8401527faaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600d602002614e84015260006020525b600e60205110156104f05760006040525b600e60405110156104e257600051600101600052631000001d60005155600051600101600052600060205160200261277401511461032f57602051602002612774015160005155610336565b6080600051555b6000516001016000526000604051602002614e8401511461036557604051602002614e8401516000515561036c565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511d60005155600051600101600052631000001b6000515560005160010160005260006020516020026127740151146103d1576020516020026127740151600051556103d8565b6080600051555b6000516001016000526000604051602002614e8401511461040757604051602002614e8401516000515561040e565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511b60005155600051600101600052631000001c6000515560005160010160005260006020516020026127740151146104735760205160200261277401516000515561047a565b6080600051555b6000516001016000526000604051602002614e840151146104a957604051602002614e840151600051556104b0565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511c600051556040516001016040526102e3565b6020516001016020526102d2565b0000 +d9dee826162f616a839ce0bfee0db9cb422a6f991c5831838d1f4142c9a3c43b=60ff60005260806000602002612774015261800060016020026127740152638000000060026020026127740152678000000000000000600360200261277401526f80000000000000000000000000000000600460200261277401527f80000000000000000000000000000000000000000000000000000000000000006005602002612774015260006000602002614e84015260016001602002614e84015260026002602002614e84015260056003602002612774015260fe6004602002614e84015260ff6005602002614e8401526101006006602002614e8401526101016007602002614e8401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6008602002614e8401527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6009602002614e8401527f8000000000000000000000000000000000000000000000000000000000000000600a602002614e8401527fa000000000000000000000000000000000000000000000000000000000000000600b602002614e8401527f5555555555555555555555555555555555555555555555555555555555555555600c602002614e8401527faaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa600d602002614e84015260006020525b6006602051101561040d5760006040525b600e60405110156103ff57600051600101600052631000001d60005155600051600101600052600060205160200261277401511461024c57602051602002612774015160005155610253565b6080600051555b6000516001016000526000604051602002614e8401511461028257604051602002614e84015160005155610289565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511d60005155600051600101600052631000001b6000515560005160010160005260006020516020026127740151146102ee576020516020026127740151600051556102f5565b6080600051555b6000516001016000526000604051602002614e8401511461032457604051602002614e8401516000515561032b565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511b60005155600051600101600052631000001c60005155600051600101600052600060205160200261277401511461039057602051602002612774015160005155610397565b6080600051555b6000516001016000526000604051602002614e840151146103c657604051602002614e840151600051556103cd565b6080600051555b600051600101600052604051602002614e84015160205160200261277401511c60005155604051600101604052610200565b6020516001016020526101ef565b0000 +e3419aa3349648119d7ac284de0dba8e063dd870c78693f5d1f977e8c7f10531=3050600d80601360003960006000f050fe00fe6211223360005260206000fd00 ec181eee16d86db526290ad3b6fed53fc942d8879b0209cbc0239c9af57a3838=7b601080600c6000396000f200600035541560095700602035600035556000526000600060006000601773aaaaaaaaace5edbc8e2a8697c15331677e6ebf0b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecf100 -5d48702bb1b7ab50547f4f7cb78d2dfbed39a5048e66ef3eeb7efab11b6a7616=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa585500 -75b623adef17d8ee945396a0e457c02de9327d43bd6530247b01dbab9e6bccda=600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d8761c350fa600101585500 +4a110a25479924a086a81ca8a92aa017b797f261f6416dff9433c2ce93fbef6d=6160a7600055600060006000600060006004355af1506160a760015500 +1ea1a1dd8fd66ed2dfe3c130ae6590fe933b92c0e1c28c8d21c104b66620fb77=6000600060006000600073a0000000000000000000000000000000000000005af160005500 +d5f3cccc5baa4f1489a77f9802821d3443fcb059dad76e3d3f1f29b3caa001a0=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206103e86080600060015afa60005560a060020a6103e851066001556001543214600255600060005260006020526000604052600060605260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060025afa6003556000516004556103e851600555600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060035afa6006556000516007556103e851600855600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060045afa6009556103e851601055600060005260006103e8526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a05260206103e860a1600060055afa6011556103e85160125560006000526000602052600060405260006060526000608052600060a05260006103e8527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d460605260406103e86080600060065afa6013556103e85160145561040851601555600060005260006020526000604052600060605260006103e8526000610408527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba602052600360405260406103e86060600060075afa6016556103e8516017556104085160185560006000526000602052600060405260006103e8526000610408527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206103e8610180600060085afa6019556103e85160205500 +9587684c7d5328f4f12a5b051bd5d226074263879c6c11ae0bda0b52db7e4ef2=366000600037655a175a175a173660006000f560005500 +5598916aa5224e161a88881cdcdf6d07e2660a4863e6a00ea4ab8bc257f3dcb0=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206103e860806000600162061a80fa60005560a060020a6103e851066001556001543214600255600060005260006020526000604052600060605260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060025afa6003556000516004556103e851600555600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060035afa6006556000516007556103e851600855600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060045afa6009556103e851601055600060005260006103e8526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a05260206103e860a1600060055afa6011556103e85160125560006000526000602052600060405260006060526000608052600060a05260006103e8527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d460605260406103e86080600060065afa6013556103e85160145561040851601555600060005260006020526000604052600060605260006103e8526000610408527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba602052600360405260406103e86060600060075afa6016556103e8516017556104085160185560006000526000602052600060405260006103e8526000610408527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206103e8610180600060085afa6019556103e85160205500 cc45a5d135a8f9e57c309064b573fd2096be276abcca0a786f138b91173c9806=58600152600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d8761c350fa00 8d4ade0d727cfb64bfa4822027a066ce0356301bebb5a84a378d2d09d9592dd9=6000600060006000346000355af1600055600160015500 +75b623adef17d8ee945396a0e457c02de9327d43bd6530247b01dbab9e6bccda=600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d8761c350fa600101585500 847517a05e83765f78c7a7f5f5c0ffd0f9aff3a2cdb0942a4c8e257546facffc=58600152600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa00 -e4affd2099ee1c5609d3fbae1291089a05099c54362e1641ce853fbe480ee806=600060006000600060006000355af1600055600160015500 -7b0711df01faf8aa85459833a5f02dbfb532a3752b3effd24a93e9a9ca544a8f=600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa600101585200 +5d48702bb1b7ab50547f4f7cb78d2dfbed39a5048e66ef3eeb7efab11b6a7616=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa585500 6c08e575b788dedaa76e338d12c265b1e21bf330070c6ff3b2de4238e6216afc=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa585500 +e4affd2099ee1c5609d3fbae1291089a05099c54362e1641ce853fbe480ee806=600060006000600060006000355af1600055600160015500 de8e6310b88f5e61bb3e1cf61e5018deb5ce849331b8d66508b4d2e68aa6a874=58600152600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa00 +7b0711df01faf8aa85459833a5f02dbfb532a3752b3effd24a93e9a9ca544a8f=600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa600101585200 3ae7d66fdc5bf050aae1b7a6aebd7b73f28a6f3a311c0d2c25ec3050c26f31c4=600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa600101585500 +c574607dad90aee6b83c3fc1665a2aaf8128ef7b9e5b3e7961b9789b47aaccb4=6000600060006000346000355af1600055600160015500 848ed1445089ed972a26f2115d5e8cff4e7f9c898926ee75e017f6da386f43b9=600160005101600052600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa00 f29a742f9be9e76aa07187a36a8e607e1eff7939468a0c57c05e5611b58e5ad4=600160005401600055600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa00 03e0f6da45fc1ce6e52182732e8d12e56722585f37958a4ecd3510d452943ffd=600160005401600055600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa00 ffa82f8e8aca8c1b0edc26428ed39999b441647e0a65c7a518e874498b50d99c=600160005101600052600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa00 -c574607dad90aee6b83c3fc1665a2aaf8128ef7b9e5b3e7961b9789b47aaccb4=6000600060006000346000355af1600055600160015500 69a88067624e01b6239912c9925d34b5f210adb5c8877b3a8aac27f36a23297b=600160005401600052600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa00 49ab705dc9bb9e656e931cf56281cab0fdc9aeb783237adc2d82105f0a1c1512=600160005401600052600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03fa00 -ca714aeb6844ef9d58ffac2ee18ec087e8355e609476156b59aea4c14a19d112=600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa585273945304eb96065b2a98b57a48a06ae28d285a71b5ff00 a504bf49be3b2eb805df90688d764167d18e692ccac80bcb0740634b3321d26c=600060006000600073195e7baea6a6c7c4c2dfeb977efac326af552d8761c350fa600101585200 +ca714aeb6844ef9d58ffac2ee18ec087e8355e609476156b59aea4c14a19d112=600060006000600073245304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa585273945304eb96065b2a98b57a48a06ae28d285a71b5ff00 04c2ed31c0bae2704c6803bbc19baca5c9573d7d3c060e8ad5aba9e90011a916=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa585573945304eb96065b2a98b57a48a06ae28d285a71b5ff00 -2de09a348bd19a028da60773913756f69431b621da433750cbb05afcb037b82b=600035600052600060006020600073945304eb96065b2a98b57a48a06ae28d285a71b5600035fa00 c82f5d265659d347880908fc2d570ab0b17bb8c30b9e9fde1f6ef665288704ec=600035600052600060006020600073095e7baea6a6c7c4c2dfeb977efac326af552d8761c35060003503fa50730f572e5295c57f15886f9b263e2f6d2d6c7b5ec6ff00 +2de09a348bd19a028da60773913756f69431b621da433750cbb05afcb037b82b=600035600052600060006020600073945304eb96065b2a98b57a48a06ae28d285a71b5600035fa00 b9df2e03df2ca660f9df81aec2385169eb7445c609863aca34808497205337d6=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60fa600155600160645500 1e35ef69787f36587d5fb72e3def7ead221ea4af0bb297a02b427daee8f3184b=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60fa00 +1559f73bf51a6bd64b56536e049892ddeaf090ff84d487076b145c18bd3450fe=5b61c3506080511015601c5760013b506001608051016080526000565b00 +0fa099c2413e5a9df168535bd5ce03c5e8cc96c6cda338fdc7ae58c4368967bd=600160015500 5b10e9929e41f007f2630f6e529ebc43513a2ec0779c11dc7cd2ebf790fe2717=6000600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b6064f100 9c1da38f1cea43836fcc7425513e0b01040c196afadfb4ff8da714f6dd5e1c89=600160015200 -0fa099c2413e5a9df168535bd5ce03c5e8cc96c6cda338fdc7ae58c4368967bd=600160015500 -1559f73bf51a6bd64b56536e049892ddeaf090ff84d487076b145c18bd3450fe=5b61c3506080511015601c5760013b506001608051016080526000565b00 8a9ea564d7839b7dfe036c25f7d6d498ef1b9efb6f370df0be73af42efc42a04=600160015200 fe1479307d0ae7d9c9a5a1f82259d21daad6a5de6f06319930318b8afd1f5736=5a600055602060006000f06001555a600255600060006000600060015461ea60fa6003555a60645500 9a25f942d2f6c17ef3b5de806a0557b10f8efc55a37fff018d937aa50cc20e05=5a6000557f600c6000556000600060006000600073c94f5374fce5edbc8e2a8697c15331676000527f7e6ebf0b61ea60f1000000000000000000000000000000000000000000000000602052604060006000f06001555a600255600060006000600060015461ea60fa6003555a60645500 @@ -2290,40 +2283,25 @@ dd805dedda7c77cd5dc10c607c92bc756a9f0a638ed5a54244154f379d6e86fe=600160005101600 cedba9ece1b60951ead1283952052936b8b1d66a24bc5f802d2735729916a308=60016000540160005560006000600060005473bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffffa60015500 451dc2391994684f6b8b47a9cfc44c55a2eb0dd2f422239ece0a3ab09e22f733=600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b610401600054046001036127105a0302fa6001556103e86000540260010160025500 150da3077e45f07d5988f29883b09b41dce5e7ca9b1abe39b2b8d1478769ddef=600160005101600052600060006000600073cbbf5374fce5edbc8e2a8697c15331677e6ebf0b610401600051046001036127105a0302fa506103e86000510260010160205200 -94a1cc3f281e9555184dbf91a78ee9ec09149feb5f2fe6895df024ed05d115f1=600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa50600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa50600160005101600052600060006000600073cbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff400 efee795e927f84fb0adb945f5fbc1ebac254360dcb44df54e75ee34087563cb6=600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa600255600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa600355600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff460015500 c2ba9556cc12434b54e02ce4e6d931d501c69c1e15a280653ceb0309894e78ac=600160005200 +94a1cc3f281e9555184dbf91a78ee9ec09149feb5f2fe6895df024ed05d115f1=600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa50600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa50600160005101600052600060006000600073cbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff400 62b40cf1ec03f6446c0e659ce2f4fc60eff2f27252e619e631114baa69c3d5b1=600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa600255600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa600355600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffffa60015500 f444095b24567cb86dff3f2bdd621d4bd1b9c308ef29aa69ca9b2309df3e0541=600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa50600060006000600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61fffffa50600160005101600052600060006000600073cbbf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffffa00 adafe30e1a94706ad47ea6e0e2ab42a3030da81f779b9638e9a9d258318f8b23=5b600a60805110156040576000600061c350600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffffa6000556001608051016080526000565b60805160015500 fbbbe23170683f5cc163cd4f233053a788d752b8028d67d44a0516a480a05c68=5b600a60805110156040576000600061c350600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffffa6000526001608051016080526000565b60805160205200 +518e8d45433cb867a63615cd667f549cd3edc3ca6de6af5355fe1f45389e1479=600060006000600060006000355af160005500 0e5e5d68ab3d2f833cc36fad088c4da9909f9df0349bc82a84d51d3847810d2c=60016000540160005561040060005410601b5760016002556045565b60006000620f4240600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b620f55c85a03fa6001555b00 a4e0406c1baf1015f08c5ebb9eb902ecb905de40083d4fa9c04a675fac554b23=60016000510160005261040060005110601b5760016040526045565b60006000620f4240600073cbbf5374fce5edbc8e2a8697c15331677e6ebf0b620f55c85a03fa6020525b00 -518e8d45433cb867a63615cd667f549cd3edc3ca6de6af5355fe1f45389e1479=600060006000600060006000355af160005500 -10719bacfaec1308b4bd28044fb36a4c9a0812149830d6efeda149861693f95d=5b61c3506080511015603e576000600061c350600073baaf5374fce5edbc8e2a8697c15331677e6ebf0b620186a0fa6000556001608051016080526000565b60805160015500 -bfa65cd1585cc6bda1710e286b92a295032f7d4ddcd78151566fbd2bebfcb1af=60005460005500 -13f6b299759885313e7393b49e55266200164ad5a227f0b370cc925e5eafa019=60005460005200 -2be93bf90fda15c9f97e8936c2ed1850d6dac4aa07c7df2805f827f73c522c56=5b61c3506080511015603e576000600061c350600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b620186a0fa6000556001608051016080526000565b60805160205500 -01949af72fe762c145eff98c001351cdc7349bbcee447154e5aa34de855fe933=5b61c3506080511015602a576000600061c350600060016101f4fa6000556001608051016080526000565b60805160015500 -5520d0b6ee348a3fa6def20f7abee815833e4517c2cedb3f0ed74567ffe71e17=5b61c3506080511015602a576000600061c350600060016101f4fa6000526001608051016080526000565b60805160205200 -5a8934f574a6c7bbd7ba0df4430e904a5fa7317ef06c908434925b72350d0352=602a6001525b61c350608051101560305761c350600161c3506000600461061cfa6000526001608051016080526005565b60805160205260015160405200 -8f84db2f4a617e227a06b6e760c38e9abd6fb02f7d864963b54ff715c0010a5e=602a6001525b61c350608051101560305761c350600161c3506000600461061cfa6000556001608051016080526005565b60805160015560015160025500 -ff28a6d325496da13bf13b1286c2bac28d242cbb4671dc55e52a9438f156987c=5b61c3506080511015602a576000600061c3506000600461061cfa6000556001608051016080526000565b60805160015500 -dcab24f69874e425a03a15c1dd84538c754982948e36ac70a61b72afa6a941fb=5b61c3506080511015602a576000600061c3506000600461061cfa6000526001608051016080526000565b60805160205200 -10fba243d2b9e0376c027da85597eb02bb534d01bd20497bf01b7803bbebfce5=5b61c3506080511015602b576000600061c3506000600362013178fa6000556001608051016080526000565b60805160015500 -edc5358740a15bdc84cce2e167aef9e9aa7eed627a320c96bed52ed19c73d704=5b61c3506080511015602b576000600061c3506000600362013178fa6000526001608051016080526000565b60805160205200 -3940e7f8e965ce1e520a0c832026a729e561e5869d7ea01d0f2c71efd4a0d16a=5b60326080511015603e57600060006000600073aaa50000fce5edbc8e2a8697c15331677e6ebf0b64148c1c2280fa6000556001608051016080526000565b60805160015500 -93f095e06aacf77c2c5e6fc7542c677813f004e8895c7ef0768cdbae6010c910=5b60326080511015603e57600060006000600073ccc50000fce5edbc8e2a8697c15331677e6ebf0b64148c1c2280fa6000526001608051016080526000565b60805160205200 -d6f522e03d8f60a565642ea04417328e1851281ecd37eb8bf23d5926f09e57ee=5b60326080511015603e57600060006000600073ccc50000fce5edbc8e2a8697c15331677e6ebf0b64148c1c2280fa6000526001608051016080526000565b60805160205200 -6a087fb788ade9003cb55a55d3910c758d4ab11e2c5d62a3de2f42618484f988=6000600060006000732000000000000000000000000000000000000103620927c0fa60095560006000600060006000731000000000000000000000000000000000000103620927c0f2600a5500 b65a639d937e5d2bf958c15440a67e4119682763bb358d0591d9da53a4716dd7=6000600060006000731000000000000000000000000000000000000103620927c0fa60095560006000600060006000731000000000000000000000000000000000000103620927c0f2600a5500 +6a087fb788ade9003cb55a55d3910c758d4ab11e2c5d62a3de2f42618484f988=6000600060006000732000000000000000000000000000000000000103620927c0fa60095560006000600060006000731000000000000000000000000000000000000103620927c0f2600a5500 6ebaf83c33c2cee3af4f96f11416c73995ddfe353b7cfe9312ab7804eb3a7ed5=601260005200 +d154d3443627ec7b9b4714482ec0c4912d141f67e1f21261a3eb342d2e115132=5a6008526000600060006000731000000000000000000000000000000000000108620927c0fa60095200 +86e34fc9f92a233255712ea4dd5596532a0b00148b10f0c867dcc2c5e91450a3=6001600855600060006000600073200000000000000000000000000000000000010762030d40fa60095500 +75f0c2ebd23355bc89911c75994a8f86f2d9b49ad6e9bb73d4b538c03b1e4d5f=5a6008526000600060006000732000000000000000000000000000000000000108620927c0fa60095200 5068499c922fdc5490952a26514b9653928a238e05efa21438bd82bdc3115f45=600160085500 40feb2b16aa5295c8d81010e6dc7712ec8bcc1f3618a0d2bd4022dc5f17ecb3a=5a60085200 -86e34fc9f92a233255712ea4dd5596532a0b00148b10f0c867dcc2c5e91450a3=6001600855600060006000600073200000000000000000000000000000000000010762030d40fa60095500 b7c05ea76a53e47443a315cdebc8d471eb1d2a8a6b5a3457b81ffb67ec948b0b=6001600855600060006000600073100000000000000000000000000000000000010762030d40fa60095500 -75f0c2ebd23355bc89911c75994a8f86f2d9b49ad6e9bb73d4b538c03b1e4d5f=5a6008526000600060006000732000000000000000000000000000000000000108620927c0fa60095200 -d154d3443627ec7b9b4714482ec0c4912d141f67e1f21261a3eb342d2e115132=5a6008526000600060006000731000000000000000000000000000000000000108620927c0fa60095200 3df6ceea3eb0ac5fd7b62ad34dc5a845fbb94db7d6778225956b191fad1f0c07=74600c60005566602060406000f060205260076039f36000526015600b6001f060005560006000600060006000546000fa60015500 054829905933d02b982db54f2071b13c66774b1e1e01c7d9880333b9d8453873=74600c60005566602060406000f060205260076039f36000526015600b6001f060005560006000600060006000546000fa00 8cf4961ea0d0e182af73c824d25be9acfe545eb446befad5c4c92c18c1f24175=74600c60005566602060406000f060205260076039f36000526015600b6001f06000556000600060006000600054620249f0fa60015500 @@ -2344,12 +2322,12 @@ b608e2bd975152e4ef474640765aeb8509e0e67131bdd4d97b1f63c1813e10a0=7f1122334455667 c26fa0477659989e854da9505974ab47978b16cde9fa9e4d24bf9c0b46ea7f61=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527eb1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206080608060006001620493e0fa60025560a060020a60805106600055600054321460015500 15479cd180bb76cade7a0e123e5c9abf66feb718b97c77a879a49ab8615baf9c=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527eb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206080608060006001620493e0fa60025560a060020a60805106600055600054321460015500 ca5ef10e7d080d96e21e5d67bbb21cb2b3cdc5fde37a738066db40eb433cdaf4=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206080608060006001620493e0fa60025560a060020a60805106600055600054321460015500 +dd44572feb385d8fe9932d59c83716c9eeb9ca62fee1056eec4a07a3b75da4b6=5b61c3506080511015601c5760013b506001608051016080526000565b00 2c480595fa5a2e2c59360c5b3822ce08adaf3651539472b08663d8546ad1d1a5=5a6008526000600060006000600035620927c0fa60095200 6d80de9a558f53c7cfcf2752f199c7ea1e8299b4896baac95e50bb86d570a996=6000356000526000600060206000731000000000000000000000000000000000000113620927c0fa600055600160015500 -dd44572feb385d8fe9932d59c83716c9eeb9ca62fee1056eec4a07a3b75da4b6=5b61c3506080511015601c5760013b506001608051016080526000565b00 -a121df53d4b2823b2745d4a3ace3494ec0bb7309aa7a4780ed6ce94151d66300=5a6008526000600060006000731000000000000000000000000000000000000111620927c0fa60095200 76789aacaf2dfca81d7141317b87b177e44d376e98c5404fe25723223a064cca=622fffff60002000 bc825613a7f1964902f53f3b26ffeb59ce6fe49afe42d1926ef34898ef1b8e40=6000600060006000731000000000000000000000000000000000000110620927c0fa6009555a600a5500 +a121df53d4b2823b2745d4a3ace3494ec0bb7309aa7a4780ed6ce94151d66300=5a6008526000600060006000731000000000000000000000000000000000000111620927c0fa60095200 dd08e0516ec849131ff41d8e91408539e388ac735e6b959d1c6be67891e74688=602060006000600060046101f4fa60025560005160005500 4b68b33216d2d7d37ec51ce5927c587ba9658842e81d8105ef08d68acc8b0656=6020600060006000600462030d40fa60025560006000600060006013600461c350f15060005160005500 f97958a82e87dfdc79164c209f8731d45bf9d1362c61a19375bd87d4bbcc20f6=64f34578907f600052602060006025600060046101f4fa60025560005160005500 @@ -2360,19 +2338,19 @@ a4032162c4796e1f1035c3324bb69c6ea0add9185870fcbccb38cf7ef7304226=7ffffffffffffff 0dad64f8e747061352994cc46b4fdfb0531ce0c2b48b3e4e290be4ed86defbb2=600160005401600055600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b620186a060005402600101fa6001556103e86000540260010160025500 fc5bcaa60198a96b3424b97c04893bc61345fafbc102838cee9e8b8c5872c116=600160005101600052600060006000600030612af85a03fa00 c40420a1ee6f77e82cb5c34fe4abdc52f2cc080aeef8498dff83a8ba71ead65c=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b56305f5e100fa600055600160015500 -100cba8d8715246e03dc7d526243a7ad966c48a10f2c7d7ec7658c6915aa83cf=600160005401600052690fffffffffffffffffff610402600051040260025260006000690fffffffffffffffffff61040260005104026000306104005a03fa00 9542ab676d0c6ce7d0c6e9416e7c2a4dd96147323a2d681b22708bf78c506ab4=6000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d875af250600160015500 +100cba8d8715246e03dc7d526243a7ad966c48a10f2c7d7ec7658c6915aa83cf=600160005401600052690fffffffffffffffffff610402600051040260025260006000690fffffffffffffffffff61040260005104026000306104005a03fa00 2058053e9a9efeae0b48503c903bc03234d323547b8b93ce24bf1f345711bb62=600160005101600052600060006000600030613a985a03fa00 58949b3211da91b07c9ad06d44d6495a4580cb346b34666d10082209e401e5fc=6000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d875af250600160015500 b468b4b9f144d1073ef24255286e8cee8bde42ee4fe9c6f48b85085b75b73f90=6000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d875af2600055600160015500 -43dcd231f392efde20b464e095660a55b5f11a9c7571ef3af56b508ea7228ba7=6000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03f2600055600160015500 2150529b7493f71d56e4819d9fb79f8db3cf440287e12eb6bc9fc6582f5e94c2=60016000540160005260006000600060003060e05a03fa00 +43dcd231f392efde20b464e095660a55b5f11a9c7571ef3af56b508ea7228ba7=6000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03f2600055600160015500 44cf7ed8d3657fc221e460d1b9887a932a77355a332f1258cde6343163272f37=5a60005260206000a06000600060006000306161a85a03fa00 fa765eadc8a248a3d70cd0b9fdba76e1c2bd5295c50d3221ccc59ecf5a74ed63=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa600055600160015500 2c96f792bb792015a367fe3dea4d767cda7e299c30c5213f8895f0621406b391=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03fa600055600160015500 8fbc02cd413bdc3aa02d26b618a1dcec05a8653178ce330fa7052c937700ed5b=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60005260206000a06000600060006000306161a85a03fa00 -798b7d5a2d0d014cae0bc7b241134c6210d3b9feca3b87b2974c23d8f62d998e=60016000510160005260006000600060003062036b005a03fa00 1a48f8ed328af49b6b4316cf8db1d7ebc81e40feae9043c165eb5a6f08f0652e=600060006000600073bad304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa50600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b56707fffffffffffffffa600055600160015500 +798b7d5a2d0d014cae0bc7b241134c6210d3b9feca3b87b2974c23d8f62d998e=60016000510160005260006000600060003062036b005a03fa00 9b9396aa9e585e07978689dc8b62ec7c725eafd0e428171285819af84e45fd97=600060006000600073bad304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa50600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b56707fffffffffffffff4600055600160015500 6bf82608cb5dea39e3ce20548dbc0573605056106a3b0bdc1167a4bf0b08fa6a=600160005101600052600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b562036b005a03fa00 487086a2f5d1e95f82d466c76f251420a060201051b91829529ff9c305d6bdff=60206000600060006003610258fa60025560005160005500 @@ -2395,111 +2373,108 @@ b5262b9f1c246c973d4f2c29992121fb22bd990c653f7c13181d67986be7a981=64f34578907f600 19494f63b9c3dfbefc0579c0f1fc986978c6368ee0a5260b4df29796b3463985=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600060406040600073945304eb96065b2a98b57a48a06ae28d285a71b5620186a0fa60005500 e0b4e92497c879e419bfb2b86d55db1049dcc392419f555d1913a19b8a77c763=6001601f6000600073945304eb96065b2a98b57a48a06ae28d285a71b56103e8fa60005560005160015500 3a33b2afaae785160d59cca8bdcf315370a57d68fe7d3b483a3f09569a3d71a1=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600260006040600073945304eb96065b2a98b57a48a06ae28d285a71b5611388fa60005560005160015500 -b81fbebd2baa32e081159c48938fa8cc62696329a332407a144f8f71b70ed53c=6001600152622fffff60002000 b2d091a3977fac39677c8ec072add00e29a503669ffd9782d00ea6dc92612069=60006000600060007320000000000000000000000000000000000000006064fa00 +b81fbebd2baa32e081159c48938fa8cc62696329a332407a144f8f71b70ed53c=6001600152622fffff60002000 +1d099e1a209c69de5aa5df2481c89515b6cc1b69231af9f2a8d3bae95c6d7f08=60006000526000600060006000600173a200000000000000000000000000000000000001620186a0f16000526001600152600160025200 +cd4f4fb73990b39df91ad313fa43a22d3c76c4b2b9a2a255dac85ba115bcdd13=600060006000600073a500000000000000000000000000000000000001620186a0f46000526000516001146036576002600155603c565b60016001525b00 82852f92116f941bace53a80171ff4aef2b70e7508bf0217ba729be9fb8c1dca=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373400000000000000000000000000000000000000114604b5760026001556051565b60016001525b30734000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600114608a5760026001556090565b60016001525b00 -6598fac36b2144a976e4e961f38735b42d9cbf37304e678a061e8428a6355e5f=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000014604b5760026001556051565b60016001525b30735000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -b4bae1f29814deb5b8ae318af163cef95fc3eb9406e5cf9cb5c05b2404092824=6000600060006000600073a100000000000000000000000000000000000001620186a0f16000526000516001146038576002600155603e565b60016001525b00 -404f9eb6bf83d63eae9918edc8e3fa7b7d91d1c8c281162e3ebc4ff7fd7940fa=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373300000000000000000000000000000000000000114604b5760026001556051565b60016001525b30733000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -6bc69fe9150c2f3cc4109f9748d5e806e632b281714fda813d393a3b49dfc841=6000600060006000600073a300000000000000000000000000000000000001620186a0f26000526000516001146038576002600155603e565b60016001525b00 f66e92c07dfed6754d35c1970a83714e4bc0afd4b2c3c6d2be2273793dd6bfa2=6000600060006000600173a400000000000000000000000000000000000001620186a0f26000526000516001146038576002600155603e565b60016001525b00 -758d97983f44fb944608801da50b9831182861e1db77739e7cb93b38073b373b=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a100000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -cd4f4fb73990b39df91ad313fa43a22d3c76c4b2b9a2a255dac85ba115bcdd13=600060006000600073a500000000000000000000000000000000000001620186a0f46000526000516001146036576002600155603c565b60016001525b00 +404f9eb6bf83d63eae9918edc8e3fa7b7d91d1c8c281162e3ebc4ff7fd7940fa=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373300000000000000000000000000000000000000114604b5760026001556051565b60016001525b30733000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 7ee389ec41c907f420e15834c14231da97e433d1c2d9cf63edf55c68c65849d3=6000600060006000600035620186a0fa60015500 -1d099e1a209c69de5aa5df2481c89515b6cc1b69231af9f2a8d3bae95c6d7f08=60006000526000600060006000600173a200000000000000000000000000000000000001620186a0f16000526001600152600160025200 +758d97983f44fb944608801da50b9831182861e1db77739e7cb93b38073b373b=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a100000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +6598fac36b2144a976e4e961f38735b42d9cbf37304e678a061e8428a6355e5f=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000014604b5760026001556051565b60016001525b30735000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +6bc69fe9150c2f3cc4109f9748d5e806e632b281714fda813d393a3b49dfc841=6000600060006000600073a300000000000000000000000000000000000001620186a0f26000526000516001146038576002600155603e565b60016001525b00 +b4bae1f29814deb5b8ae318af163cef95fc3eb9406e5cf9cb5c05b2404092824=6000600060006000600073a100000000000000000000000000000000000001620186a0f16000526000516001146038576002600155603e565b60016001525b00 333b6ab0b37d67d33f0d7f98cd5be36363440995b6c2867733ae35f8325bc711=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373200000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a200000000000000000000000000000000000001146074576002600155607a565b60016001525b34600114608a5760026001556090565b60016001525b00 -3b84f25377a4292b9e4f7b1fbc695c55a0c90a25ef625a01d76461d936a4a1e2=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373b00000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a100000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 d9099ee8b971d5cfff89f8f538c03a7dc0db58ac2c15eb282b3a490fb6ebab54=73a500000000000000000000000000000000000001600052600060006020600073b000000000000000000000000000000000000001620186a0f4600052600051600114604e5760026001556054565b60016001525b00 -fede4d962d1269c9642938e02ddb5cfec17e2699590faae4d4e71aee7d0009ce=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373300000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a300000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -3e76ea67b634ad55e3c5a485cf4ec19b8c31d252da94477e142b56e10bac0550=73a3000000000000000000000000000000000000016020526000600060406020600073b000000000000000000000000000000000000001620186a0f260005260005160011460505760026001556056565b60016001525b00 57b4bb4a6cdf644ff79a4f0616ec39a559001128c1f801d817854a3ad163a859=73a1000000000000000000000000000000000000016000526000600060206000600073b000000000000000000000000000000000000001620186a0f160005260005160011460505760026001556056565b60016001525b00 dd9bbe198fa3c3f386b5fa54577aa2df29323f665ee5701c4fff0df49662225f=73a4000000000000000000000000000000000000016000526000600060206000600173b000000000000000000000000000000000000001620186a0f260005260005160011460505760026001556056565b60016001525b00 -893fdb92897484a363c0727c19c79f18ebbded0ae77bdf253e86049a9ff18c37=6000600060006000600035620186a0fa6000526000516001146024576002600155602a565b60016001525b00 +d6d980714c607a88cb51370f544420aefaf837fd5066c1260a06898ec3714989=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373500000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a500000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 ea4a267b25f60eb4da367c26f8ccd520958d24e4094f4cbd1a2611b1abd625e4=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373400000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a400000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +893fdb92897484a363c0727c19c79f18ebbded0ae77bdf253e86049a9ff18c37=6000600060006000600035620186a0fa6000526000516001146024576002600155602a565b60016001525b00 fec8703d9ae566b4ed571b0841440a97b05c473c43f1f67cf70c6b8b8645e646=73a1000000000000000000000000000000000000016000526000600060206000600173b000000000000000000000000000000000000001620186a0f16000526001600152600160025200 -d6d980714c607a88cb51370f544420aefaf837fd5066c1260a06898ec3714989=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373500000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a500000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -adf9f5e900872addcd20976752fa8c397bd63527cd62e41ad2884f10e2e22de9=6000600060006000731000000000000000000000000000000000000001620186a0fa6001556000600060006000731000000000000000000000000000000000000002620186a0fa6002553360035534600455326005553060065500 +fede4d962d1269c9642938e02ddb5cfec17e2699590faae4d4e71aee7d0009ce=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373300000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a300000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +3e76ea67b634ad55e3c5a485cf4ec19b8c31d252da94477e142b56e10bac0550=73a3000000000000000000000000000000000000016020526000600060406020600073b000000000000000000000000000000000000001620186a0f260005260005160011460505760026001556056565b60016001525b00 +3b84f25377a4292b9e4f7b1fbc695c55a0c90a25ef625a01d76461d936a4a1e2=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373b00000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073a100000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 a0a9ad09b174a0e4b69fd8e66e3538164ef7f66206e3e61ea165eb9404f75b5c=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000014604b5760026001556051565b60016001525b30731000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +adf9f5e900872addcd20976752fa8c397bd63527cd62e41ad2884f10e2e22de9=6000600060006000731000000000000000000000000000000000000001620186a0fa6001556000600060006000731000000000000000000000000000000000000002620186a0fa6002553360035534600455326005553060065500 98a8f573ecd230d28465b6ae3ec5958c28c7fd153e67a05c7277cd4ea862f628=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000014604b5760026001556051565b60016001525b30731000000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -4541ff509f4b7f945bfbb98bfc5c9a5d24b0ea229a33f66a2b8ff30a55ba1d36=73b0000000000000000000000000000000000000026000526000600060206000600a73a000000000000000000000000000000000000002620186a0f100 -fdc379e7a00f997a69a26b3e5111261b02b9a43dde5f67400e1244f288a45f63=73b0000000000000000000000000000000000000026000526000600060206000600073a000000000000000000000000000000000000002620186a0f100 -62ed67099b2a0a74b3c9a5c69708fd2e705ce40103205bdf48c02cc44ff795f4=73c4000000000000000000000000000000000000026000526000600060206000600173a000000000000000000000000000000000000002620186a0f200 -e4de4eb0dac078a046039bbea1e5b917af7de4f852be503d9cd871d4b8ceea93=600060006000600060003561c350fa60005500 -2e7f9ae3b2d4a46fc16e0a417b8562802fc3d41504ef2ac83c5fe3b88ae06175=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373300000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c300000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 e6833afb60bec0da2d810a52522e631d53e19fa2b77f83f5a8b06a2133185be3=600060006000600060006000356203d090f160015500 -c70e6cd29563926bb175ad7acebc55c469d5b5df8a99b82ad3df330ae8580133=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373400000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c400000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -5cb5e5a7280bc21b84bd72fd523c26b90bad35b2e8de1077a2d48eae4c13940e=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373500000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c500000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -5e9e34dec2ea7ebe341e51daa89b9da17cab841d1caa960179a0c6c282ffd6c8=73c3000000000000000000000000000000000000026000526000600060206000600073a000000000000000000000000000000000000002620186a0f200 87bc076915cabd26d946ac8ff1d7ef9f1490d8c3d912cf9baa9c74fe74992b45=73c500000000000000000000000000000000000002600052600060006020600073a000000000000000000000000000000000000002620186a0f400 +2e7f9ae3b2d4a46fc16e0a417b8562802fc3d41504ef2ac83c5fe3b88ae06175=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373300000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c300000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +fdc379e7a00f997a69a26b3e5111261b02b9a43dde5f67400e1244f288a45f63=73b0000000000000000000000000000000000000026000526000600060206000600073a000000000000000000000000000000000000002620186a0f100 +5e9e34dec2ea7ebe341e51daa89b9da17cab841d1caa960179a0c6c282ffd6c8=73c3000000000000000000000000000000000000026000526000600060206000600073a000000000000000000000000000000000000002620186a0f200 ca56f36ac47069406dbd2855d9d6f06d0cf047655c766ce2d20ab1fa3cfc7856=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373a00000000000000000000000000000000000000214604b5760026001556051565b60016001525b3073b000000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 -1f49a79208f808b39c987e3b9a37e06ea7e0037376dc3fe45b453f2f1b19f5f3=6000600060006000731000000000000000000000000000000000000003620186a0fa00 +c70e6cd29563926bb175ad7acebc55c469d5b5df8a99b82ad3df330ae8580133=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373400000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c400000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +e4de4eb0dac078a046039bbea1e5b917af7de4f852be503d9cd871d4b8ceea93=600060006000600060003561c350fa60005500 +5cb5e5a7280bc21b84bd72fd523c26b90bad35b2e8de1077a2d48eae4c13940e=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373500000000000000000000000000000000000000114604b5760026001556051565b60016001525b3073c500000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +4541ff509f4b7f945bfbb98bfc5c9a5d24b0ea229a33f66a2b8ff30a55ba1d36=73b0000000000000000000000000000000000000026000526000600060206000600a73a000000000000000000000000000000000000002620186a0f100 +62ed67099b2a0a74b3c9a5c69708fd2e705ce40103205bdf48c02cc44ff795f4=73c4000000000000000000000000000000000000026000526000600060206000600173a000000000000000000000000000000000000002620186a0f200 46cfad55e6cbc241c831a87943487a7f8d3ff08287d0728812eca0b8ad5e9622=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000214604b5760026001556051565b60016001525b30731000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +1f49a79208f808b39c987e3b9a37e06ea7e0037376dc3fe45b453f2f1b19f5f3=6000600060006000731000000000000000000000000000000000000003620186a0fa00 def5a1a160fb678f39f631f5ea5031be5d2f6a89f4e7acc87fdf8f647813076f=6000600060006000600035620927c0fa60015500 ef66cde67e17bb3af5f101543f93df462bfa5ec7d2f5b7d459d4b4f1e63d50c1=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b6161a8fa60015500 6d779126382ca62b73d591ad0230bda4701f11eb9b4e9c15aef8a9dc1e9fdcad=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b611388fa00 -8dfe910571b05e7844a2639e820bf06265e148fc042a6dddebd527a876cc7c7e=60006000600060006000619c40fa60015500 18876880f90eb8ce2efdb8d0a929af959598c6a5d1a6b956a690dfff06a33009=600060005560006001556000600255600060035560006004556000600555600060065560006007556000600855600060095500 +8dfe910571b05e7844a2639e820bf06265e148fc042a6dddebd527a876cc7c7e=60006000600060006000619c40fa60015500 f0a42cef1d3367adecb417fddfe30066452b568dd64eed7a67a74cd80a2c451a=60006000600060006000731000000000000000000000000000000000000000620186a05a03f1600055600160015500 -55c56c0457696b45ea272ebaa736e6aa2d5a09f24adc2b3e731ee01896371c8a=600060006000600073b0000000000000000000000000000000000000005afa00 a0f6b36645b102ba27d6bb08d20028bc9e1a027b2889cbf272845f825aa0ac88=600060006000600073a0000000000000000000000000000000000000005afa00 +55c56c0457696b45ea272ebaa736e6aa2d5a09f24adc2b3e731ee01896371c8a=600060006000600073b0000000000000000000000000000000000000005afa00 c84ec6b401222601c68ccddf2f4cb0dc5daf3815e2cc85de439948e7f6ff979a=6103526000526000600060206000600073a0000000000000000000000000000000000000006127105a03f1600055600160015500 318f3bc4238b8114f152600cf9fdc7bd6771f8f066a72d613c06071fa23cd7c1=60005160010160005200 6083b5f500257ccd1475297c47c0142c27992657c96be39c8518e78943d3f54b=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600060006040600073945304eb96065b2a98b57a48a06ae28d285a71b5617530fa60015560005160025500 639df5cf6341d6b4c631c0237f9bf4779e4fc65ce032bd73f2494793ea32708b=60006000600060007310000000000000000000000000000000000000016707fffffffffffffffa60015560006000600060007310000000000000000000000000000000000000026707fffffffffffffffa60025560006000600060007310000000000000000000000000000000000000036707fffffffffffffffa60035560006000600060007310000000000000000000000000000000000000046707fffffffffffffffa60045560006000600060007310000000000000000000000000000000000000056707fffffffffffffffa60055560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60065560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60075560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60085560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60095560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600a5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600b5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600c5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600d5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600e5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600f5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60105500 54e49fc3421fb9c8baa336e22373997544c2384a364621f58cb3f6293d0464ef=60006000600060007310000000000000000000000000000000000000016707fffffffffffffffa60015560006000600060007310000000000000000000000000000000000000026707fffffffffffffffa60025560006000600060007310000000000000000000000000000000000000036707fffffffffffffffa60035560006000600060007310000000000000000000000000000000000000046707fffffffffffffffa60045560006000600060007310000000000000000000000000000000000000056707fffffffffffffffa60055560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60065560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60075560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60085560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa60095560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600a5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600b5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600c5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600d5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600e5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa600f5560006000600060007310000000000000000000000000000000000000066707fffffffffffffffa6010556000600035146102af575a6102b7565b622fffff6000205b00 -7d62497b16e28a08693cef3aea82332aa0b1561781d889c69cf955622c557dde=600060006000600073094f5374fce5edbc8e2a8697c15331677e6ebf0b622dc6c0fa505a60015500 bda26e862bfee374bea68999f70d8e5842cc79afc545ddba0af90cb2a383258b=600060006000600073094f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0fa505a60015500 -037054064d2afc539fe9ed7ccb779971403d394ce2bcfbcbe999c5fbb09b5f96=5a60005200 +7d62497b16e28a08693cef3aea82332aa0b1561781d889c69cf955622c557dde=600060006000600073094f5374fce5edbc8e2a8697c15331677e6ebf0b622dc6c0fa505a60015500 097b9519ac8275905c177e3b6f7cc42b63bbaa224382603f1baa61db996b6d53=611f406000611f40600073094f5374fce5edbc8e2a8697c15331677e6ebf0b622dc6c0fa505a60015500 34676a20c227fbeb2467c2781ea554fb488bbe4c1b820cba1e9a12b99e6b6406=611f406000611f40600073094f5374fce5edbc8e2a8697c15331677e6ebf0b6201fbd0fa505a60015500 -fcf0011747d36a5b88c1fc5f7acd46799013ea6d1742be5ecb02f37ecad5a23e=61c34f356000526001600051f300 -31d87b82490b345887422d30c21c0ce23b669af6171f9d386e845f68fdc272f7=6000600060006000600073bbbf5374fce5edbc8e2a8697c15331677e6ebf0b5af1600055600160015500 -f140a8b34b63f89d692af5c19b602aec3e72d4c8cd47c487a984c934583add67=5b61c3506080511015603d576000600061c350600073aaaf5374fce5edbc8e2a8697c15331677e6ebf0b61061cfa6000556001608051016080526000565b60805160015500 +037054064d2afc539fe9ed7ccb779971403d394ce2bcfbcbe999c5fbb09b5f96=5a60005200 2f32bfbb2e5247f725e01a4151857de7cabd85f8da8a135394402ac23f913774=6015600052602060206020600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b611b58fa5060005160005560205160015560406000f300 358f48d33170ae527eb2db1e7a59eaf9d5cca8797c10de562e117136502cf231=6001601f6001601e73b94f5374fce5edbc8e2a8697c15331677e6ebf0b6107d0fa506000516000556002601ef300 -13c00864a3879ed5f8d801b044d0edb2db81ecb48eb35ea08961c8e18dd466ba=600060006000600073c00000000000000000000000000000000000000061c350fa50600160015200 -f893caffc84199ad12a96155f4955dbc2c9fe5eed0fa06f9b42e3364eb38cf35=600054600101600055600060006000600073b000000000000000000000000000000000000000620249f0fa600155600060006000600073d000000000000000000000000000000000000000620249f0fa60025500 7a5df1bde40bb02b724eafff4243f6134e6e7d3526333fe9f8c1c85ea370818d=600060006000600073c00000000000000000000000000000000000000061c350fa50622fffff60002000 -ce064fd2d509a2a0db6f14d867a25cdccf0d953da247155bb71531503b66a2e3=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350fa6000553d60015500 +f893caffc84199ad12a96155f4955dbc2c9fe5eed0fa06f9b42e3364eb38cf35=600054600101600055600060006000600073b000000000000000000000000000000000000000620249f0fa600155600060006000600073d000000000000000000000000000000000000000620249f0fa60025500 +13c00864a3879ed5f8d801b044d0edb2db81ecb48eb35ea08961c8e18dd466ba=600060006000600073c00000000000000000000000000000000000000061c350fa50600160015200 50b35dca6e8923fb30f02c47e37dd62e6bdaeefc968557c43a54f742f72bddc3=60016000fd00 +ce064fd2d509a2a0db6f14d867a25cdccf0d953da247155bb71531503b66a2e3=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350fa6000553d60015500 f3e5f529719929897d5d04c7b0cdbe69ec76bfe6aebba78cd50ccf82343e7308=5a600055600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60fa600155622fffff600020505a60645500 -6c9893edc37020e5544719f667e6d96a047f452a16abf2012732cc80e3b14692=73c94f5374fce5edbc8e2a8697c15331677e6ebf0bff00 fe3cc22b069757e210195ba7849dce069c1bc14d0f9ac7bc1536ae26d0d92ba0=600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b620186a0fa50622fffff60002000 -6034354c9b6e85bc2acc17ebb92030ce865861ae2a27ac1d07844358c8f3966c=60006000600060006001733000000000000000000000000000000000000003619c40f250600160015200 -f947f4791642e13dacac38aaf6f22eef10019f8b3d1f4181a4b77cae1d1ac35f=60006000600060006000732000000000000000000000000000000000000003619c40f150600160015200 +6c9893edc37020e5544719f667e6d96a047f452a16abf2012732cc80e3b14692=73c94f5374fce5edbc8e2a8697c15331677e6ebf0bff00 5474525e8a4ea3b05ca1910e3be360becdef41f627bb6f49e1843f55c899b3cf=600a6001a0600160015200 8fede10b0db14fe3e0d42fecb434cd7a7d3ae283dbbb63e5d821961500107361=6000600060006000600035620186a0fa600055600160015500 7115c22971934f96b6570f7e3aa596bb52d623ffb9c43aff0907bfc83ae6fb20=600160015500 +6034354c9b6e85bc2acc17ebb92030ce865861ae2a27ac1d07844358c8f3966c=60006000600060006001733000000000000000000000000000000000000003619c40f250600160015200 +f947f4791642e13dacac38aaf6f22eef10019f8b3d1f4181a4b77cae1d1ac35f=60006000600060006000732000000000000000000000000000000000000003619c40f150600160015200 efcbe7cad146b3569f6f9ed022c67902de9346ebf2b9dbbf170169d1c8441535=6000600060006000600060003562055730f100 +20779731aefa455ec0d2a73e6dd65d49097e17935e96551f94116d28e20ffc25=60006000600060006001731000000000000000000000000000000000000001620186a0f16000556000600060006000731000000000000000000000000000000000000001620186a0fa60015560006000600060006001731000000000000000000000000000000000000001620186a0f160025500 f5219dd69682938778c67a55be416d2a8cb7ce6606c81f9f84b825e12596d207=600160015200 -1c0c7da972d6d49d681e09bbbcbbb1fc7dcab9c32316d8016a0337311aef6cf9=60006000600060006001731000000000000000000000000000000000000001620186a0f16000556000600060006000731000000000000000000000000000000000000001620186a0fa60015560006000600060006001731000000000000000000000000000000000000001620186a0f16002555b61c3506080511015608f5760013b506001608051016080526073565b00 c10efa0cbca70244752be297ca37f60917710b83d4b1be7cd5d34735be272749=60006000600060006001731000000000000000000000000000000000000002620186a0f16000556000600060006000731000000000000000000000000000000000000002620186a0fa60015560006000600060006001731000000000000000000000000000000000000002620186a0f160025500 81da54faf4b0963c7813553b36a4c6c47cae9d75126b211993e84f83f9156485=600160015260015460015500 -20779731aefa455ec0d2a73e6dd65d49097e17935e96551f94116d28e20ffc25=60006000600060006001731000000000000000000000000000000000000001620186a0f16000556000600060006000731000000000000000000000000000000000000001620186a0fa60015560006000600060006001731000000000000000000000000000000000000001620186a0f160025500 +1c0c7da972d6d49d681e09bbbcbbb1fc7dcab9c32316d8016a0337311aef6cf9=60006000600060006001731000000000000000000000000000000000000001620186a0f16000556000600060006000731000000000000000000000000000000000000001620186a0fa60015560006000600060006001731000000000000000000000000000000000000001620186a0f16002555b61c3506080511015608f5760013b506001608051016080526073565b00 f567658186b9fcfcc93374e8b6b6c3888747b8a676569d572b0f833ef1f79fd5=60006000600060006000600035620927c0f100 -184c22c4d3b69c05d98a7888a713a908bc8fa4a3c0524ed972798a1df246524d=6d6460016001556000526005601bf3600052600e60126001f06000556000600060006000600054620493e0fa60015500 ad6840ba504c8dca4fd3c27940133e7f437ac30748b8ecc256f4817a43954267=600060006001f06000556000600060006000600054620493e0fa60015500 +184c22c4d3b69c05d98a7888a713a908bc8fa4a3c0524ed972798a1df246524d=6d6460016001556000526005601bf3600052600e60126001f06000556000600060006000600054620493e0fa60015500 2a3b69feb75aad4db6f3008ae9c18771ce6d868e5649242fd14db009847ce1d8=6d6460016001556000526005601bf3600052600e60126001f06000556000600060006000600054620493e0fa6001555b61c3506080511015604b5760013b50600160805101608052602f565b00 c162de6a05cb28543af03d0fdcdbd4afaa8dc91627e8d951d30890f03c08b28f=766d600060006000600030620186a0fa600052600e6012f3600052601760096001f06000556000600060006000600054617530fa600155600160025500 -373127720fce833627b38d2114f193a8adeabb9d3228a1458399c665c67b8a82=6000600060006000731000000000000000000000000000000000000002620249f0f400 -9c5629db4116e8b9ee4529087d3132274afd004cb5d6a9c975e696785820c364=6000600060006000731000000000000000000000000000000000000002620249f0fa00 -dece64523169799927485282e2fb02181ec6935ad838ddc51b11be52bd5101de=60006000600060006000731000000000000000000000000000000000000002620249f0f100 bab3a4ca0f0d3f77feea2d4793233f045bf315fe47f579fee2d2dd241ce192a6=600160016000f000 024a0cb9c27cdf47846d83d334c827a21d20974fe1c1cbbcc62f739bb0a07b60=6000600060006000600035620493e0fa60005500 +dece64523169799927485282e2fb02181ec6935ad838ddc51b11be52bd5101de=60006000600060006000731000000000000000000000000000000000000002620249f0f100 +373127720fce833627b38d2114f193a8adeabb9d3228a1458399c665c67b8a82=6000600060006000731000000000000000000000000000000000000002620249f0f400 +9c5629db4116e8b9ee4529087d3132274afd004cb5d6a9c975e696785820c364=6000600060006000731000000000000000000000000000000000000002620249f0fa00 2f7920b36306229d530687f7eca3244cb65799eb14fcbafe7a6923e44212308e=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350fa5060005160005500 f56bfbe6b2842f1010a7139b0bacab690f400ac718429a8d12cde6c54e3b396b=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600060006020600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350fa5060005160005500 efc9308c2a34f83b2767bf47bdbd05a6867d7cae92e0ffc09862b842eec8e0a0=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052602060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350fa5060005160005500 0aa22eb4acc24219c0c94948b65c062352a4a77862c669dcadfd56efe48c54d7=7f5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6600052600a60006000600073aaae7baea6a6c7c4c2dfeb977efac326af552d8761c350fa5060005160005500 b06fe602262b042548fa44e76b9295acc2952d28206385c9e67347d1a89dd95f=6000600060006000600035620186a0fa60005500 -4fb0bde6147b7281a0ed0205b519c2c569f4280507f6e678747805ea9ac929bd=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000114604b5760026001556051565b60016001525b30731000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 4b0ed9836107b1329850e71c8c4996b671b6f519a521ba8e05457e55ad4fa6c3=60006000600060006000731000000000000000000000000000000000000002620186a0f26000526000516001146038576001600155603e565b60016001525b00 -802c7ddf3b32e2f65e55845250538d5e7502ede4769c36c0d55cc2f48eaf317a=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000114604b5760026001556051565b60016001525b30731000000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 +4fb0bde6147b7281a0ed0205b519c2c569f4280507f6e678747805ea9ac929bd=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000114604b5760026001556051565b60016001525b30731000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 e0a4ebf1aad3532ab57071d51cbac3950a28db80dfacef64d3f18b29e320e723=60006000600060006000731000000000000000000000000000000000000002620186a0f16000526000516001146038576001600155603e565b60016001525b00 +802c7ddf3b32e2f65e55845250538d5e7502ede4769c36c0d55cc2f48eaf317a=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000114604b5760026001556051565b60016001525b30731000000000000000000000000000000000000002146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 48f7bb89bf24e39f4e6a8fdde75e16afd9e340770e6ad10a7f50dc4e5653600e=6000600060006000731000000000000000000000000000000000000002620186a0f46000526000516001146036576001600155603c565b60016001525b00 4b09828843cc97f3ebe8366dd6d58b458d4db4ebbdf08a36a51fd91e3d8d626a=3273a94f5374fce5edbc8e2a8697c15331677e6ebf0b1460225760026001556028565b60016001525b3373100000000000000000000000000000000000000014604b5760026001556051565b60016001525b30731000000000000000000000000000000000000001146074576002600155607a565b60016001525b34600014608a5760026001556090565b60016001525b00 bc8fbd8026656526c8a4c4740804bcbf30242133f1017f5a11c4adb16c196101=6000600060006000731000000000000000000000000000000000000002620186a0fa6000526000516001146036576001600155603c565b60016001525b00 -770a7da5d03a877e5569478a32fe9faa47dcff9cfea041326718e8beb8f2ae1a=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600260006040600073b45304eb96065b2a98b57a48a06ae28d285a71b56bfffffffffffffffffffffffffa60005560005160015500 273b9c83b9e6837aacaaf9d5ab1a3435f2cd460d8d8b62e24294906cd77c64f8=600060006000600060006000356207a120f100 +770a7da5d03a877e5569478a32fe9faa47dcff9cfea041326718e8beb8f2ae1a=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600260006040600073b45304eb96065b2a98b57a48a06ae28d285a71b56bfffffffffffffffffffffffffa60005560005160015500 3ef2444fa2b3daeb1a7d270d4ce04d5b1d80ce37437d04ff69fa0032b34d7f24=7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6000527faaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa602052600260006040600073945304eb96065b2a98b57a48a06ae28d285a71b56bfffffffffffffffffffffffffa60005560005160015500 9645880325e712facf18c761a16f9a38c5ce47466da9e94ce97750c6637a057c=600060006000600073945304eb96065b2a98b57a48a06ae28d285a71b5622dc6c1fa60005560005160015500 221710d943fb41ef7392a65dd3437e16e9eab8b9653406e4a4f46358c86b98ad=600260006040600073945304eb96065b2a98b57a48a06ae28d285a71b561c350fa600055600160015500 @@ -2509,285 +2484,285 @@ c62e60fc7991dacd07ddfd072a372ca4b4ae04834fcccf52407067f16496170d=600160006000600 68db2808557a587eb39bf7032a6daeb8f16cffa68127a01739657a6e083463da=602060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350fa60005560005160015500 c3d241b2d7d6df2e8a3bb5dafb4d8aef3b57ca7da39a22626598159f9a7cfc0e=3460005260206000f300 95676c7e03b016f7dc9709c8ab4c1a36f1d8f6aac6370a232dfd90965b932a72=6000600060006000600a73094f5374fce5edbc8e2a8697c15331677e6ebf0b620186a0f100 -b7ad6bdf4604f9b8b757bfe05fc4ba38e10467d7d42755f7dcecce6e9530d574=60406000604060007310000000000000000000000000000000000000026203d090fa00 -efd0f30d72ee28f69abbbede2fea8c18ee14287e120bf79298326b0755248753=60406000604060007320000000000000000000000000000000000000026203d090fa00 +c825eb8fb8c7d5e7333ed863327b648155c9ba1604e96cd2331e542043147066=6001600052336020523460405230606052326080523660a0523860c0523a60e05200 0540bc699d4dd5b0fa3fdb6efd5b7ceefa1b6d3cce742aedb30ce5396e218694=604060006040600073200000000000000000000000000000000000000162055730fa60005500 c4b8deae984aa5efa988bad6491930ff406a7685f87e5a4480b49b10eda1d492=604060006040600073100000000000000000000000000000000000000162055730fa60005500 -c825eb8fb8c7d5e7333ed863327b648155c9ba1604e96cd2331e542043147066=6001600052336020523460405230606052326080523660a0523860c0523a60e05200 +b7ad6bdf4604f9b8b757bfe05fc4ba38e10467d7d42755f7dcecce6e9530d574=60406000604060007310000000000000000000000000000000000000026203d090fa00 +efd0f30d72ee28f69abbbede2fea8c18ee14287e120bf79298326b0755248753=60406000604060007320000000000000000000000000000000000000026203d090fa00 475445062a8cf19a64a93251f1496ddc035ddf1d3501085b598c29f711ddd65e=60016002526040600060406000732000000000000000000000000000000000000002614e34fa50600160205200 -bf76068be5cbdd2c3bc4457cdf2a51627b1611a16f0db15efab83799fec63dbd=5b61c3506080511015601c5760013b506001608051016080526000565b00 0d4950aaa1ad9b0da6182d02ccdd623c45ffeaf725f3f02c035ce9b07ad8ff3c=600160025260406000604060007310000000000000000000000000000000000000026201d4d4fa50600160205200 43027427ed708586ce8369748f012aee319639dbc13862ef35e6758474f4dfcc=6001600255600160025200 +bf76068be5cbdd2c3bc4457cdf2a51627b1611a16f0db15efab83799fec63dbd=5b61c3506080511015601c5760013b506001608051016080526000565b00 0e24e02427a8e83c8536e59980af01ea90a99ee69a0e6e8e9c78595bf5069796=6040600060406000732000000000000000000000000000000000000001620249f0fa60005500 9b0917aa70e74b7a3fdee1ab3685a8f2bb3d67a2e22ef4e1ff7e6fb46cd1b9f1=60016002526040600060406000732000000000000000000000000000000000000002620186a0fa50600160205200 -0350d4c406bbfc1aad8dd7e25e859c0464b5310206cc0ad8ed407a1a4b1a4ebc=5b61c3506080511015601c5760013b506001608051016080526000565b00 f9d01335d8b800beefecb45a651309be0032a55978e09d8885a3f8a73c05dcf3=60016002526040600060406000731000000000000000000000000000000000000002620186a0fa50600160205200 -89dd62dafb714bb10931b9cb0574f03473f13c6754485aa5dcee061fc35e4188=6040600060406000731000000000000000000000000000000000000001620249f0fa60005500 55dec7cefedba450204c1fa7b3b8cd7f714986da078e4a7cfb258b75cdff51c6=60016002553460055500 -97f5b7335c421b410bfd81628a8aa34a518662cd4a9557511718c845bcb913a1=60016002526040600060406000732000000000000000000000000000000000000002620186a0fa50600160205200 +89dd62dafb714bb10931b9cb0574f03473f13c6754485aa5dcee061fc35e4188=6040600060406000731000000000000000000000000000000000000001620249f0fa60005500 +0350d4c406bbfc1aad8dd7e25e859c0464b5310206cc0ad8ed407a1a4b1a4ebc=5b61c3506080511015601c5760013b506001608051016080526000565b00 a3a22b67827c10d53c308beb9aa880b926a6e7b2be5dabffc019492549a2033a=60016002526040600060406000731000000000000000000000000000000000000002620186a0fa50600160205200 +97f5b7335c421b410bfd81628a8aa34a518662cd4a9557511718c845bcb913a1=60016002526040600060406000732000000000000000000000000000000000000002620186a0fa50600160205200 e1c54b74c6d6e9606beae5fa041264d84e877eaa3aacd60cf2248c2ebc635c4b=600160025200 d417f5e802616309071f6240ecfb572fbac573a4a1302cb560a13ab9db54313f=6001602052604060006040600073100000000000000000000000000000000000000261c350fa50731000000000000000000000000000000000000000ff00 -c4a016d328743cacfb9b5b56a32359bb310ca5eeba7ac2cf55a4c56e1d61f4ec=60016003526040600060406000732000000000000000000000000000000000000002620493e0fa50600160205200 1c123276d0c78004ecc4b697fdca7a2f8471bba878a800d994589440648d6b02=6001600352604060006040600073100000000000000000000000000000000000000262061a80fa50600160205200 +c4a016d328743cacfb9b5b56a32359bb310ca5eeba7ac2cf55a4c56e1d61f4ec=60016003526040600060406000732000000000000000000000000000000000000002620493e0fa50600160205200 608b30da060f19e5fc9e5d61f053f9328419e69eb55e1e047ef5c794a46870ed=60406000604060007310000000000000000000000000000000000000016209eb10fa60005500 -d97da057751123f2962112c654c0ef960c9bb07824891565d269b23fca4b50d6=600160035260406000604060007320000000000000000000000000000000000000036203d090fa50600160205200 aa4ee1aba16e5ec7311ebafdb9a904ef0f85d6e03a988740aa8b6154a042e4b4=600160035200 ebab6cfa1bd31444a856b975c84cecd01192b10d0ae549de5c5157421ced65f3=600160035260406000604060007310000000000000000000000000000000000000036203d090fa50600160205200 -3adbf55988966011734f99fd354b5f5060d6ef2e26eaa536f7073f28f896e919=600160035260406000604060007320000000000000000000000000000000000000036201d4d4fa50600160205200 +d97da057751123f2962112c654c0ef960c9bb07824891565d269b23fca4b50d6=600160035260406000604060007320000000000000000000000000000000000000036203d090fa50600160205200 666da63f5fd3ab6bd27a0b52c3ef64ca80ca09a7b19156ed8a98ccc39da63dc1=6040600060406000731000000000000000000000000000000000000001620927c0fa60005500 -897e2856814c86522ec62ec68aa3854bbb296e9f4344509ee40ef880d035a5d8=600160035260406000604060007310000000000000000000000000000000000000036201d4d4fa50600160205200 -0da1e7c490f7ab109d2b4d4403422f7b69e872c06663fcc367152053a71bd546=60406000604060007310000000000000000000000000000000000000016207a120fa60005500 -9939830cf46abeb56072966cb23bd36fa74c759cdb3d4e9927696fcf58d7c342=5b61c3506080511015601c5760013b506001608051016080526000565b00 c664866980e1fe34d66555a12a11c700443137875c513dae8560a35d7ce52451=60016003526040600060406000731000000000000000000000000000000000000002620493e0fa50600160205200 +0da1e7c490f7ab109d2b4d4403422f7b69e872c06663fcc367152053a71bd546=60406000604060007310000000000000000000000000000000000000016207a120fa60005500 b849c540c6aba10657a3a41940664b59713131e1f77b94296cd06898d5a61082=6001600355600160035200 +9939830cf46abeb56072966cb23bd36fa74c759cdb3d4e9927696fcf58d7c342=5b61c3506080511015601c5760013b506001608051016080526000565b00 32f981e49e2bf55449a299597dd2dd99a2f0f84b15b1a2ba150851330292f499=60016003526040600060406000732000000000000000000000000000000000000002620493e0fa50600160205200 +3adbf55988966011734f99fd354b5f5060d6ef2e26eaa536f7073f28f896e919=600160035260406000604060007320000000000000000000000000000000000000036201d4d4fa50600160205200 +897e2856814c86522ec62ec68aa3854bbb296e9f4344509ee40ef880d035a5d8=600160035260406000604060007310000000000000000000000000000000000000036201d4d4fa50600160205200 cf13fb5722b4a8985f42be5ed89f861c4a3a7062f99ea272cc8b9082cd69901d=6040600060406000731000000000000000000000000000000000000001620aae60fa6000556001606f5500 -ad1ee4098d7c69488a4fd01896a5f80b174952b5441237a8530b8adb63683f70=600160035260406000604060007310000000000000000000000000000000000000036201d4d4fa50600160205200 1b4f611b885a40174a01499c4b21aa8c1007f4f54a7d31225cc1a5b972507efa=600160035260406000604060007310000000000000000000000000000000000000026206ddd0fa505b61c350608051101560445760013b506001608051016080526028565b00 -ed71de6e2f3390d6c2d109755f0e145366ac1c9eadd322ec8175da3dd631a077=600160035260406000604060007310000000000000000000000000000000000000036201d4d4fa50600160205200 +ad1ee4098d7c69488a4fd01896a5f80b174952b5441237a8530b8adb63683f70=600160035260406000604060007310000000000000000000000000000000000000036201d4d4fa50600160205200 9a36b1a0b4a42e7597949bdc3f4de43d7bcc03d596a9bcaccf37d767bb138004=6001600352604060006040600073100000000000000000000000000000000000000262061ad0fa50600160035500 +ed71de6e2f3390d6c2d109755f0e145366ac1c9eadd322ec8175da3dd631a077=600160035260406000604060007310000000000000000000000000000000000000036201d4d4fa50600160205200 655c5f203b56cf8a6ceeeecd79aeeaf34123b11bad8304a394ae71f5435459b3=604060006040600073100000000000000000000000000000000000000162092856fa6000556001606f5500 186822b494b604d7c7c1057eb6b150e7c9eeada500f72204647ff8fd3bc941d6=604060006040600073100000000000000000000000000000000000000262061ad0fa00 -b83f615d1696590a7ec4f1eac553cf448d43aacb673bd8157b785fd7d96745e1=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060007310000000000000000000000000000000000000036201d4d4fa00 74a61aa710c4800f07a12eca87ae6bc0bf81c55f7dcfd2b74550728fdca64693=6040600060406000731000000000000000000000000000000000000001620927c0fa600055600160015500 -6888874442bc917f71d01f5f084db2c729e88e53b009416512b04b602a7964b8=60016003526040600060406000731000000000000000000000000000000000000002620186a0fa50600160205200 +b83f615d1696590a7ec4f1eac553cf448d43aacb673bd8157b785fd7d96745e1=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060007310000000000000000000000000000000000000036201d4d4fa00 e025a502fa40535c61169eb1f08b3af3178c5425ad2869fdfb1afbb6aa12d7d8=6040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 -ab014f21cbf2b3399565c003383739c0d065011cf33c294534c6760d98d40374=6001600352604060006040600073100000000000000000000000000000000000000361c350fa50731000000000000000000000000000000000000001ff00 +6888874442bc917f71d01f5f084db2c729e88e53b009416512b04b602a7964b8=60016003526040600060406000731000000000000000000000000000000000000002620186a0fa50600160205200 c7a09115226858fd260a49d16e4d014933a2dbb76991bc073444ae738ae2804c=600160035200 +ab014f21cbf2b3399565c003383739c0d065011cf33c294534c6760d98d40374=6001600352604060006040600073100000000000000000000000000000000000000361c350fa50731000000000000000000000000000000000000001ff00 4a6e960d19852283c7b72f20fa7b04a88b051d7a3a613063709e1140d3c0be3d=6040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 dc31386900fa73974feded44a0f16b4f7aa29e6dd2291eed72a741ccbcf968c1=731000000000000000000000000000000000000000ff604060006040600073100000000000000000000000000000000000000361c350fa00 afd1db53c3f5b489497a200ff589aeb007d9979d0bfd33eead6ee0732c95e02b=60016003526040600060406000731000000000000000000000000000000000000002620f4240fa50600160045200 -690ca0710fb92000f668d54aaf7784300930602b36dc94246ebacba4779bfd5b=600160055260406000604060007310000000000000000000000000000000000000016207a120fa50600160065200 915a92c2026d93de0dffa46b7f37c7003694e3daa65fa556f4c4547a51cd1d76=6001600152604060006040600073100000000000000000000000000000000000000163017d7840fa50600160025200 -afc9088819610f696ff1c705d58e85123fa8c72d603a1dc1d4bd6e13a7a1f5ec=604060006040600073100000000000000000000000000000000000000162055730fa600055600160035200 -f332cc951eee86dba59a8b9d2c93d96d40801c25c6068c3bb59fa3ee23d73126=600160035260406000604060007310000000000000000000000000000000000000036203d090f450600160035200 -6938c921e3d5b48ac019c8d0ed785c8f64885bfa7717c8c7fca15a949ab56c55=60016003526040600060406000732000000000000000000000000000000000000002620493e0fa50600160035200 +690ca0710fb92000f668d54aaf7784300930602b36dc94246ebacba4779bfd5b=600160055260406000604060007310000000000000000000000000000000000000016207a120fa50600160065200 3974d5c71fb125a5353bd7c8c9b5ff93aa74a5a403969d8de6fef553ff4e3621=60016003526040600060406000731000000000000000000000000000000000000002620493e0fa50600160035200 34d8761a05f3b29aeed5ec35a59210bbd9e9f0c2682576ae4f8b6f17a48306b4=600160035260406000604060007320000000000000000000000000000000000000036203d090f450600160035200 +6938c921e3d5b48ac019c8d0ed785c8f64885bfa7717c8c7fca15a949ab56c55=60016003526040600060406000732000000000000000000000000000000000000002620493e0fa50600160035200 +afc9088819610f696ff1c705d58e85123fa8c72d603a1dc1d4bd6e13a7a1f5ec=604060006040600073100000000000000000000000000000000000000162055730fa600055600160035200 +f332cc951eee86dba59a8b9d2c93d96d40801c25c6068c3bb59fa3ee23d73126=600160035260406000604060007310000000000000000000000000000000000000036203d090f450600160035200 e0d4cd5d2b6fc5d75301ed128b521e335217fcca93bb3e84dbe30e00911122e2=6040600060406000731000000000000000000000000000000000000002620493e0fa50600160035200 +b1f105737da31e39a435ccaca14d45bf7e966acbc89eeb4764ae931a356d241f=631122334460015200 +c44f8a8322b00c2fe45a25d8bc8e7f33d4634728f787647dd49d75d89a2ea020=6000600060006000346000355af1600055600160015500 a31685be6bc50872842b673c12b8f715652d15ab4538b870ddf4115f18a3108a=6040600060406000732000000000000000000000000000000000000002620493e0fa50600160035200 e5c21c6a73892cae374036c87ccb93503567dbcf8c17767cd3824b7a43c50a71=6001600452604060006040600060007320000000000000000000000000000000000000036203d090f250600160065200 -c44f8a8322b00c2fe45a25d8bc8e7f33d4634728f787647dd49d75d89a2ea020=6000600060006000346000355af1600055600160015500 -b1f105737da31e39a435ccaca14d45bf7e966acbc89eeb4764ae931a356d241f=631122334460015200 -a05c66c87a3743060902db9fba58f6c002ba1225a11fd85c2910fa251231a54f=60016003526040600060406000731000000000000000000000000000000000000002620493e0fa50600160035200 44eeb1e90b4ba9f1cac8c855b777bcb4509d5d53263e3169665463b112fd41d8=6040600060406000731000000000000000000000000000000000000001620927c0fa600055600160035200 28259b787a771ce6a0442343dd8508b2f94ae391ba33b12365bbc17035c31e86=600160035260406000604060007310000000000000000000000000000000000000036201d4d4f450600160035200 +a05c66c87a3743060902db9fba58f6c002ba1225a11fd85c2910fa251231a54f=60016003526040600060406000731000000000000000000000000000000000000002620493e0fa50600160035200 +f2b73c66f8a6365168230f9d8247a482c901ecbbdbe08004170c0f3db9e37930=6040600060406000731000000000000000000000000000000000000002620493e0fa00 be303a6b604153d86b8c041aee03c5165c4bab158dabd63ee408e525b9f7075b=60406000604060007320000000000000000000000000000000000000016207a120fa60005500 -1fc33a3065a274a1c4731b2fff9fc4675309e557131d61b3b7700559fef1e467=604060006040600060007320000000000000000000000000000000000000036201d4d4f200 cc253b8464df96b5902144db47ffe52e42c74685b5e822b763190c301567b369=6040600060406000732000000000000000000000000000000000000002620493e0fa00 -f2b73c66f8a6365168230f9d8247a482c901ecbbdbe08004170c0f3db9e37930=6040600060406000731000000000000000000000000000000000000002620493e0fa00 +1fc33a3065a274a1c4731b2fff9fc4675309e557131d61b3b7700559fef1e467=604060006040600060007320000000000000000000000000000000000000036201d4d4f200 afb1b47797335e53cdc9467108080e6922ad005f3893e38d751df01e2d0998ae=604060006040600060007310000000000000000000000000000000000000036201d4d4f200 722d286ead0dd8fb456e399a368af1ff1c3d3fda619eeee098f598331525ec43=604060006040600073100000000000000000000000000000000000000262061ad0fa505b61c3506080511015603f5760013b506001608051016080526023565b00 4fe53d29306665adcdc638aac6d0830318fcb19dd679c4978ddc158a39fe62ce=604060006040600060003562092856fa600055600160015500 -e1e34b26e94d0b8a399a402d540ce9f6e2db126c89fe0cde67f9b2f4a6f2268f=604060006040600060007310000000000000000000000000000000000000036201d4d4f200 b7e895641c3007eb44a637b315aaab9539bd1209e7ad346ef2f9e80fd3b28d24=604060006040600073100000000000000000000000000000000000000262061ad0fa50600160035500 +e1e34b26e94d0b8a399a402d540ce9f6e2db126c89fe0cde67f9b2f4a6f2268f=604060006040600060007310000000000000000000000000000000000000036201d4d4f200 e9b485a251e321f74d917400db4546485a0fb9f5fecd094bae4a389c2ef43eef=6001600352604060006040600073100000000000000000000000000000000000000262061ad5fa505b61c350608051101560445760013b506001608051016080526028565b00 -4624e38fce300e82ef08e25d4899c2466721ac24f7c5ea4a9fe205a62f59ae1d=6001600352604060006040600073100000000000000000000000000000000000000262061ad5fa50600160035500 81a3559f95be565bc43fdfbd30daa82a89fc86a2e92f2b9e23981bfd8f76c8c9=600160035260406000604060007310000000000000000000000000000000000000036201d4d4f450600160205200 +4624e38fce300e82ef08e25d4899c2466721ac24f7c5ea4a9fe205a62f59ae1d=6001600352604060006040600073100000000000000000000000000000000000000262061ad5fa50600160035500 +f31c205d634922344829da12de3086733e58f603fc31710c158ae456b674e668=604060006040600073100000000000000000000000000000000000000262061ad5fa505b61c3506080511015603f5760013b506001608051016080526023565b00 37c4eee477383998a832fdf28353f590e48b27123b300ed399f77700b5978111=604060006040600073100000000000000000000000000000000000000262061ad5fa50600160035500 74962fff62c0a4ce03d6cd31c1a58b749a196d66f630dbeb9629ac96720e0e53=604060006040600060003561eaf6fa600055600160015500 8978a0facc7ef4be4cbc5d2efd03de84172f3a1d8ac0bf9d139cf395e97dc94b=60406000604060007310000000000000000000000000000000000000036201d4d4f400 -f31c205d634922344829da12de3086733e58f603fc31710c158ae456b674e668=604060006040600073100000000000000000000000000000000000000262061ad5fa505b61c3506080511015603f5760013b506001608051016080526023565b00 7230fdd3981b30ed76ae2d327857920cc937ed84661768eb1accfa1e54af4027=604060006040600073100000000000000000000000000000000000000262061ad0fa505b61c3506080511015603f5760013b506001608051016080526023565b00 -dfe22b1d3adeb26a4aae00560b744af4e53df3590769e33b40ae24a161a2d7ca=6001600155604060006040600060007310000000000000000000000000000000000000036201d4d4f200 7d0f9af9265451fd3a0b5f7ee1b9aedd7995514c8a1e0fee49bba65b1b0dac43=6000356000526040600060206000731000000000000000000000000000000000000001620927c0fa600055600160015500 3174b7ef817680780a83ec454c7bcc5f4e9ea56d126b34a8b0eb3a08d0da64bc=5b61c3506080511015601c5760013b506001608051016080526000565b604060006040600060007310000000000000000000000000000000000000036201d4d4f200 17e38df7ed7bc33d107911adb4149ad591f78f654ab9f3108e7f4eb129ae545d=600035600052604060006040600060003562061ad0fa50600160205200 +dfe22b1d3adeb26a4aae00560b744af4e53df3590769e33b40ae24a161a2d7ca=6001600155604060006040600060007310000000000000000000000000000000000000036201d4d4f200 86b171a421431c31a2203461b78bcb590c97261d0ac766f1f54935b182345557=6000356000526040600060206000731000000000000000000000000000000000000001620927c0fa600055600160015500 e3b86e973eca920d41f0bd75d8b31bf41d234e6b076fafbab5e5569c82173211=6001600352604060006040600060003562061ad0fa50600160205200 ddb2857153071a4a369737061fd85a778889ed4352e2bad25d238af15f27da16=600160015560406000604060007310000000000000000000000000000000000000036201d4d4f450600160035200 85b2d690a5cc162c8288585b95a381f31e83a3a57b5d76b331bbb5287a199f20=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060007310000000000000000000000000000000000000036201d4d4f450600160035200 -911368bbead45abe1065427b032be1a7be045bb631176c25902e6ae4b1431a4f=6040600060406000731000000000000000000000000000000000000002620186a0fa00 af026713c0f79ed0f9422542314b76c2d987cd460191945ade6291ddb324edcf=6040600060406000600073100000000000000000000000000000000000000361c350f250731000000000000000000000000000000000000001ff00 +911368bbead45abe1065427b032be1a7be045bb631176c25902e6ae4b1431a4f=6040600060406000731000000000000000000000000000000000000002620186a0fa00 0d5110e79e7e7f1610af81d144f95ebf1490c262b2061ac5b1abb732d64ba8e2=604060006040600073100000000000000000000000000000000000000361c350f450731000000000000000000000000000000000000001ff00 4c7bd946f52be4d844bd55901ae229f48a66a1e42d9e8a9d930426186b6b4b98=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f200 dbfcfc8a4c91780172921929c09e091ce397db603c05f886d3f79e89d6ad46ab=731000000000000000000000000000000000000000ff604060006040600073100000000000000000000000000000000000000361c350f400 -1b1811f756816d2ddee4caeb1cae16252329ca9b8df4246f662aadbc43f989c2=60016001526040600060406000731000000000000000000000000000000000000002620f4240fa50600160025200 394e474a7818369aa6ef906be0c6644a95a9e29478f9cfbaa2a03daea59ec68c=6001600152604060006040600073100000000000000000000000000000000000000163017d7840fa50600160035200 +1b1811f756816d2ddee4caeb1cae16252329ca9b8df4246f662aadbc43f989c2=60016001526040600060406000731000000000000000000000000000000000000002620f4240fa50600160025200 55bfae0c08eb128e982de648f2205254221e7f93b84741f952ce7faf60c6659a=6001600152604060006040600060007310000000000000000000000000000000000000016207a120f250600160025200 913cd9fcc69b0cf2717ce54e52ff7877c6e8ec8f533d876543d5c3e139b02ae8=6001600152604060006040600073100000000000000000000000000000000000000163017d7840fa506001601f5200 031cbc6008876a2d3377154417571f4bd0a820a4b3ebc05da64fe4fb644a91bf=60016001526040600060406000731000000000000000000000000000000000000002620f4240fa506001601f5200 86543023e3a738c6eed5c0789fced34f74e0df473c78279763720c442e2449ac=600160015260406000604060007310000000000000000000000000000000000000016207a120f450600160155200 -fa604d7cc74787b4e22cc5feeca594bd39651e1edaa4fd04713fa589e3111a36=600060006000600060006000355af2600055600160015500 +1eead44955d81c4eb2d0d7701f660a59433e9b3772dac184e3fab15e1df3aa47=604060006020600060027310000000000000000000000000000000000000026203d090f200 +3911b30490a024a2f85a5a6c7e83be797ba997cf4865c1ee1a12000990c863fc=600035600052604060006020600060007320000000000000000000000000000000000000026203d090f200 91ca3f0a794a613cb00a5af2f8b9b51f435bb74f6aedd6a0fdc67d32c548d487=631122334460005200 +fa604d7cc74787b4e22cc5feeca594bd39651e1edaa4fd04713fa589e3111a36=600060006000600060006000355af2600055600160015500 bc9d5eb5e687e81d4337eebe298cf5ac56ba9af338be51564798fdf4629f9586=604060006020600073200000000000000000000000000000000000000162055730fa00 b4240ea416e844fc377d42e2baf78f2786934b0b4a0297accacecb853e036fe4=604060006020600073100000000000000000000000000000000000000162055730fa00 -1eead44955d81c4eb2d0d7701f660a59433e9b3772dac184e3fab15e1df3aa47=604060006020600060027310000000000000000000000000000000000000026203d090f200 -3911b30490a024a2f85a5a6c7e83be797ba997cf4865c1ee1a12000990c863fc=600035600052604060006020600060007320000000000000000000000000000000000000026203d090f200 e3fb774d92546b939d025710375a6f30e2878f68981bdfd0d7ad941ee5b8077a=6000356000526040600060206000731000000000000000000000000000000000000001620249f0fa600055600160015500 c32a492feef390c6e2ebdcf786710b75f0249803127aa9cc425195423625c4eb=60406000604060006000600035614e34f200 d90ca2ba7240aa1702a9340556d3b024e2ca470fec0a3e5c001f1bcdfafda78c=6040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 3a891e03c400cb4fb705e70bebbb1467bf91e052c1e435b21d9bd7488851fdfd=6040600060406000600073100000000000000000000000000000000000000261c350f250731000000000000000000000000000000000000000ff00 941d4ad354c546f28461fe3422f954a5d8c347d075d192ca40fe1a0e4b136b37=604060006040600073100000000000000000000000000000000000000261c350f450731000000000000000000000000000000000000000ff00 +28a8dbcbc1d87f9fde6d57eca021a131effe99fb866ec78a845c85a37c1bb212=600160035260406000604060007310000000000000000000000000000000000000036203d090fa50600160035200 28debc2190ba10fe2437f4826b554e8c2983a2613eea29bd17a61b38b202cee6=60016003526040600060406000731000000000000000000000000000000000000002620493e0f450600160035200 -ffd7cbda91ff075896082246f9efe599b8ce72bf6dbcfa5463fab4834e385b37=604060006040600073100000000000000000000000000000000000000162055730fa600055600160015500 7fd91a367a1410a3d1a44cfcdda30bf0bffc24c9fb7d8f28d4cda4aebf7f0151=600160015200 -28a8dbcbc1d87f9fde6d57eca021a131effe99fb866ec78a845c85a37c1bb212=600160035260406000604060007310000000000000000000000000000000000000036203d090fa50600160035200 -01110d9d56ce4b24560dfdc4cd4079811e32e4e2845bf7b7f1fa6ff7bb98d189=60406000604060007310000000000000000000000000000000000000036203d090fa00 +ffd7cbda91ff075896082246f9efe599b8ce72bf6dbcfa5463fab4834e385b37=604060006040600073100000000000000000000000000000000000000162055730fa600055600160015500 755f1aa3078eab6342ea35bb1c5ebd1f6dba37cf197a46931cb3502703e50523=604060006040600060003562055730fa600055600160015500 -f3315867b1ff03330818d4979ec692d60632b26a926cb8f04060bd2297d4a592=60406000604060006002731000000000000000000000000000000000000002620493e0f200 8cd5f1da0a54544f60ab0932eb3a546866e047ad1b287cebc999bfad87b20908=60406000604060006000731000000000000000000000000000000000000002620493e0f200 +f3315867b1ff03330818d4979ec692d60632b26a926cb8f04060bd2297d4a592=60406000604060006002731000000000000000000000000000000000000002620493e0f200 +01110d9d56ce4b24560dfdc4cd4079811e32e4e2845bf7b7f1fa6ff7bb98d189=60406000604060007310000000000000000000000000000000000000036203d090fa00 efd3791362262abf08729a7d7eed41b0b9e211ee0d7e2d63e26dfafa8dd3605b=60406000604060007310000000000000000000000000000000000000036201d4d4fa50600160015500 7106b6684160e262c6124439eed57fb5417859e6fe917de72eb194bde1f294f2=60406000604060007310000000000000000000000000000000000000036201d4d4fa505b61c3506080511015603f5760013b506001608051016080526023565b00 e6cec50e7f4fd14feca1d0152300545600b9184f9af222b92ee1ea39705a6b5f=60003560005260406000604060007310000000000000000000000000000000000000016207a120fa600055600160015500 9d493cf39585e380242a5e78d876bb72bc7a6e1932d14388f8707f4edc2eb4b5=6040600060406000600035620493e0f450600160015200 +959780bdbe849e75c2983634a537636aa539fc57bac17f51354eff7a8442415a=60406000604060006000356201d4d4fa00 3eeda39518c12c58d883cee18c09bf06998f0e8cc586a87c6ae2f1e8dee4cff7=5b61c3506080511015601c5760013b506001608051016080526000565b00 -c3c01fcf216aa9d8a37eaddf379db38ae881981f63616b2d2e460bc0a5cd5bcb=600035600052604060006020600073100000000000000000000000000000000000000162055730fa600055600160015500 f61c7e415147d3786daec93e883995af444dc4b87d9f5e2fc90f247d7a31c4cd=6000356000526040600060206000600073100000000000000000000000000000000000000262030d40f200 -959780bdbe849e75c2983634a537636aa539fc57bac17f51354eff7a8442415a=60406000604060006000356201d4d4fa00 -e351411758140bbda208c47f21a717c14592bb69887f75acb72450640718fafe=6040600060406000600073100000000000000000000000000000000000000262061ad0f2505b61c350608051101560415760013b506001608051016080526025565b00 -36d372f01e14a26d3739f0a66ab218dce8adf2fe7d8f7663672aa209bfc501ef=60406000604060007310000000000000000000000000000000000000036201d4d4fa00 +c3c01fcf216aa9d8a37eaddf379db38ae881981f63616b2d2e460bc0a5cd5bcb=600035600052604060006020600073100000000000000000000000000000000000000162055730fa600055600160015500 2626635253531004e0083e5ab107a55b0da18c00d0e63d11dd231f922b3a64a0=604060006040600060003561eaf6fa600055600160015500 +36d372f01e14a26d3739f0a66ab218dce8adf2fe7d8f7663672aa209bfc501ef=60406000604060007310000000000000000000000000000000000000036201d4d4fa00 +e351411758140bbda208c47f21a717c14592bb69887f75acb72450640718fafe=6040600060406000600073100000000000000000000000000000000000000262061ad0f2505b61c350608051101560415760013b506001608051016080526025565b00 6612d3591ca5cff6424dfc7ecf672bd0476b338f0c45349467e83ebdf8180dc9=6040600060406000600073100000000000000000000000000000000000000262061ad0f250600160015500 +2a9cd3f540828b9d7f10518a4986822deaef29110d4a4e9b214167d3dd422135=60406000604060007310000000000000000000000000000000000000036201d4e8fa00 27711706af4e7c525eb52c15796c712d0c11e595ec37fe8e85a91c401f6b4191=604060006040600073100000000000000000000000000000000000000262061ad0f450600160035500 7016b75b4fe8b619967eb8c1368c2465918b0165d4c5704c54e0be85982c1e69=604060006040600073100000000000000000000000000000000000000262061ad0f4505b61c3506080511015603f5760013b506001608051016080526023565b00 -2a9cd3f540828b9d7f10518a4986822deaef29110d4a4e9b214167d3dd422135=60406000604060007310000000000000000000000000000000000000036201d4e8fa00 4d1c50f95e2e5a62d0d80afa50d74bf47549c34141e979880ba45ed74c09380a=6040600060406000600073100000000000000000000000000000000000000262061ad0f250600160035500 +a3fc2a1912421434d65d63c44b9276655cfdcd7b63f2ad5aebde3a6eb1871f91=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060007310000000000000000000000000000000000000036201d4d4fa00 79d11cbc7e13370c339c4b6cf861c79ea723d013dc56ce97450cd3123d80b801=60016003556040600060406000731000000000000000000000000000000000000003614e34fa00 -f0165c8201e02783fc98137d70eaf711d12c99d88ddfc41ddedf99443e54d612=6000356000526040600060406000731000000000000000000000000000000000000001620c3500fa600055600160015500 b77cbcf2dc17a2d2e64fd93462fae09f85f9441231f9e1011807b7f92ae2dc80=6040600060406000600060003562061ad0f200 -a3fc2a1912421434d65d63c44b9276655cfdcd7b63f2ad5aebde3a6eb1871f91=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060007310000000000000000000000000000000000000036201d4d4fa00 +f0165c8201e02783fc98137d70eaf711d12c99d88ddfc41ddedf99443e54d612=6000356000526040600060406000731000000000000000000000000000000000000001620c3500fa600055600160015500 7ef175fe7268e1628cbe09e3bffb1760c2d2642000ff5a2fadd85aa2b4e2fab4=604060006040600060003562061ad0f400 -9c05c56c35679d36fbefc4cfedf1eb9eec0ec59f91f8314511afa4ddd53a4d79=600160035560406000604060007310000000000000000000000000000000000000036201d4d4fa00 a71d4709c30594846e170a0199776c922f7a2f3053bd4c4623195f33d8354880=5b61c3506080511015601c5760013b506001608051016080526000565b6040600060406000731000000000000000000000000000000000000003614e34fa00 +9c05c56c35679d36fbefc4cfedf1eb9eec0ec59f91f8314511afa4ddd53a4d79=600160035560406000604060007310000000000000000000000000000000000000036201d4d4fa00 898daa0dde418d103f87750e94ad28510cf1d2c3eaa2019adb161607c3f345cc=604060006040600073100000000000000000000000000000000000000361c350fa50731000000000000000000000000000000000000001ff00 330bcfcd9070b4879165e359c0952305d4b5de189f5b283b73556d46c8aa89fe=60406000604060006000731000000000000000000000000000000000000002620186a0f200 0ca686a3596a517253fb3eed546559ea48bafe95f1255e56636e57ce9b4f206d=6040600060406000731000000000000000000000000000000000000002620186a0f400 81ce17c01b81feaac753e31bbaa6c5962927200ac16e21614ed904a5aa58ba59=731000000000000000000000000000000000000000ff604060006040600073100000000000000000000000000000000000000361c350fa00 -2345251fc06998d6100c332efdce916fd61069881ca2746b9e7fccb71889ae97=60406000604060006000731000000000000000000000000000000000000002620f4240f200 ad8b9a8ada9cbea6549060796d360654180d999b61ce823716bc6dccb3eb130b=60406000604060007310000000000000000000000000000000000000016207a120fa00 +2345251fc06998d6100c332efdce916fd61069881ca2746b9e7fccb71889ae97=60406000604060006000731000000000000000000000000000000000000002620f4240f200 aa752032f8023793e2ce90a566d8261ce682b60cdd57dea16d2faf17ba0e0530=604060006040600073100000000000000000000000000000000000000163017d7840fa600055600160015500 b91f8f6f60072a26c6702cc3940f64a191ee88199bde844e7320eba342270219=60406000604060007310000000000000000000000000000000000000016207a120fa00 a8b4e47486764e10c92491f389d0e9f039c49387f0bfc4f7b0cddc13ed91d258=6040600060406000731000000000000000000000000000000000000002620f4240f400 -15427cf6c2f1cda400a5e22ae9352fbbcde451223c2ba8874824fc20ee3831e2=60016001526040600060406000731000000000000000000000000000000000000002620493e0f450600160015200 d737cfe4f473b358e4bbf25b675defdfbad5d0feb5e579fa2a6bd8b8e33cb928=604060006040600073100000000000000000000000000000000000000162055730fa600055600160015500 +15427cf6c2f1cda400a5e22ae9352fbbcde451223c2ba8874824fc20ee3831e2=60016001526040600060406000731000000000000000000000000000000000000002620493e0f450600160015200 f2d6dba9b905bd2faa31322899c65419ba6fec6a6e2ced2f1dd968952b410dcd=6001600b5260406000604060007310000000000000000000000000000000000000036203d090f4506001600b5200 a83f4b1e886937bf2e59f33acd445d05b75c06e7fca6a40cf211fca04cc46035=600035600052604060006040600073100000000000000000000000000000000000000162055730fa600055600160015500 +f0bf62e3b1074f38f203640db7bbdb0cd29f2d7da3cda308f15cde20e882bac9=60406000604060006000600035620493e0f200 7e7a1fbba5a24ab8b99a1c587c7f936f2d6c9173affaa3fdec27dde16301ee71=604060006040600060007310000000000000000000000000000000000000036203d090f200 de74252bf18ef8d8ef2a0c4426609537173ab8e6b8a8267f4aa024512551a308=604060006040600060017310000000000000000000000000000000000000036203d090f200 -f0bf62e3b1074f38f203640db7bbdb0cd29f2d7da3cda308f15cde20e882bac9=60406000604060006000600035620493e0f200 -6a0b6c3956ea8d7f09ceb59ffd67d87ab7c83ed2ea24c18dd36fa368927b68d9=6000356000526040600060406000731000000000000000000000000000000000000002620186a0f400 9e5fa0550d8e6448c9d7ed44098020a5d8259fb54c0df41c4e49b80b87f0fff7=6000356000526040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 +6a0b6c3956ea8d7f09ceb59ffd67d87ab7c83ed2ea24c18dd36fa368927b68d9=6000356000526040600060406000731000000000000000000000000000000000000002620186a0f400 9e493073ffb1d3f2fafa1ab6c4e12c8d50e90b7f6c5f8265bcabe708a1d3f49a=6040600060406000600035614e34f400 be3c1b374105a1ad263bf482a34d194340e256d9e9caffae33a1d8eac752de9b=600b60035260406000604060006000731000000000000000000000000000000000000003614e34f2506001600d5200 -773de79017408de6196b8092ec68a270308777e85196fb7f8d7a3adf15eaf984=600160035260406000604060006000600035620186a0f250600160035200 d785046261ef2b2c902e001004a68d692bd4ef92f80a1ad2d038c947bcf79b30=600b60035260406000604060006001731000000000000000000000000000000000000003614e34f2506001600d5200 -2ad769b31a685c24a9813ff218ab0c162e73904096cee987a83cbc91f7910ac6=60406000604060006000731000000000000000000000000000000000000002619c90f250600160035500 +773de79017408de6196b8092ec68a270308777e85196fb7f8d7a3adf15eaf984=600160035260406000604060006000600035620186a0f250600160035200 716e7b90937b670d0f8861902e63aa3ca135e3bb31db95139ed4dcff4516d0ad=60406000604060006000731000000000000000000000000000000000000002619c90f2505b61c350608051101560405760013b506001608051016080526024565b00 +2ad769b31a685c24a9813ff218ab0c162e73904096cee987a83cbc91f7910ac6=60406000604060006000731000000000000000000000000000000000000002619c90f250600160035500 3ee90542e7dac7319fdc339bca415439887d15ba46aef52574fb4fd444e1736a=60406000604060006000731000000000000000000000000000000000000003614e34f200 63ddc6c7cde8118fe54c30fd9fc1cb826c13964e4e018ed18a95115d1f667420=60016001526040600060406000731000000000000000000000000000000000000002619c90f450600160035500 -02a39c0ea5cfcd25758f8478f2eed90a6cf897e5f78fa2ac736d5a14e76ddbe9=60016001526040600060406000731000000000000000000000000000000000000002619c90f4505b61c350608051101560435760013b506001608051016080526027565b00 -6a377ab9663a733e2d19a51cc67035ed2cf988848e1958613920c61678d8981b=60016001526040600060406000731000000000000000000000000000000000000003614e34f450600160015200 9bd2b9edcce1e8c22477108d177cf7bb0a8c937fd056509b0e3813f861660733=604060006040600060003561eaecfa600055600160015500 -e10487259f293e94299500b7b3ae77caa62ff12bd1558573151cca375536d2c9=60016003526040600060406000731000000000000000000000000000000000000003614e34f450600160035200 +6a377ab9663a733e2d19a51cc67035ed2cf988848e1958613920c61678d8981b=60016001526040600060406000731000000000000000000000000000000000000003614e34f450600160015200 +02a39c0ea5cfcd25758f8478f2eed90a6cf897e5f78fa2ac736d5a14e76ddbe9=60016001526040600060406000731000000000000000000000000000000000000002619c90f4505b61c350608051101560435760013b506001608051016080526027565b00 19344224a8deb0fa8e82e94a09aeb02e7e820970a78c254a0cbc8a70621232f9=60016003526040600060406000731000000000000000000000000000000000000002619c90f450600160035500 +e10487259f293e94299500b7b3ae77caa62ff12bd1558573151cca375536d2c9=60016003526040600060406000731000000000000000000000000000000000000003614e34f450600160035200 0a2c796d5cbdaf129fb6d80cf80513a1dd595b0c5f675d754ff0e658d3c09154=60016003526040600060406000731000000000000000000000000000000000000002619c90f4505b61c350608051101560435760013b506001608051016080526027565b00 -2e49a6a0d257b972358b3b47343bf3fca517c29627ae610a084eba25df4b3665=600160035260406000604060006000731000000000000000000000000000000000000003614e34f250600160205200 c30f2919b4c2b7d30b6872d74fea80089c40b9fd88392074e369dd88a6e8ac78=600160035260406000604060006000731000000000000000000000000000000000000002619c90f250600160035500 +2e49a6a0d257b972358b3b47343bf3fca517c29627ae610a084eba25df4b3665=600160035260406000604060006000731000000000000000000000000000000000000003614e34f250600160205200 f927fe9f4febe484192375e0cb1a95db93295e98d2d2ff5114dae3a562cf76fc=600160035260406000604060006000731000000000000000000000000000000000000002619c90f2505b61c350608051101560455760013b506001608051016080526029565b00 4996d25cdcb6aee5f3542bb02aef18224e2ce46faf8d21484b6cf4fddbaef153=60406000604060006001731000000000000000000000000000000000000003614e34f250600160205200 +1035e4a30d74279c5322335b9a804376a8791f7704fee5e5e2abe2c8a69a4a25=600160035560406000604060006000731000000000000000000000000000000000000003614e34f250600160205200 36ef1ee3541797068fa8fb591658e5247ff437d1039a9ea43e8e6a92f0e67158=600160205200 2bc0daa50656548f8bb288c4162fe1ff516e80f60357203625403a33391f58d6=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060006000731000000000000000000000000000000000000003614e34f250600160205200 -1035e4a30d74279c5322335b9a804376a8791f7704fee5e5e2abe2c8a69a4a25=600160035560406000604060006000731000000000000000000000000000000000000003614e34f250600160205200 cf91a54add743885c763456b67470db07e8637c921d01d36d02dc8147b41aa45=600160205260406000604060006000600035619c90f250600160205200 +596076fbb6f5a523e367c612a3f0a760389aa32b2e2c3c493e08f293709284a6=5b61c3506080511015601c5760013b506001608051016080526000565b6040600060406000731000000000000000000000000000000000000003614e34f450600160035200 aa174be1ab553fb83733662264927bf27e9a130167b31b2b2b65d2d7ac664604=60016003556040600060406000731000000000000000000000000000000000000003614e34f450600160035200 c80166c3731db7b3358f05e480910feacd1b883cd4bd69168a23aceec1707a9f=6000356000526040600060406000731000000000000000000000000000000000000001620249f0fa600055600160015500 0d282f2ca4d6fa58b776906b97ec17f4320c928bef222d3bc31c47c3ebb5cfdb=60016003526040600060406000600035619c90f450600160035200 -596076fbb6f5a523e367c612a3f0a760389aa32b2e2c3c493e08f293709284a6=5b61c3506080511015601c5760013b506001608051016080526000565b6040600060406000731000000000000000000000000000000000000003614e34f450600160035200 -9302404ae67eacca7bccb8ce9db8ad39bb93f78aa516219470c0ee3cbb4846e9=60016003526040600060406000600073100000000000000000000000000000000000000361c350f250731000000000000000000000000000000000000001ff00 c3b941b3fe17595e21ebc4a42723044fe3e8a9b8b31da85497b7d2b6e2d4987a=600160035260406000604060006000731000000000000000000000000000000000000002620186a0f200 -c0cc692ef46a185404ff734f2c5076bfda4a55fa1ea5cf1dbea81af30b8ae7f6=600160035260406000604060006000731000000000000000000000000000000000000002620186a0f250600160035200 +9302404ae67eacca7bccb8ce9db8ad39bb93f78aa516219470c0ee3cbb4846e9=60016003526040600060406000600073100000000000000000000000000000000000000361c350f250731000000000000000000000000000000000000001ff00 bc19b7fd8dc1fa147fecd948973aceb2960745fbc40991f8d09f3dda415c4269=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f250600160035200 +c0cc692ef46a185404ff734f2c5076bfda4a55fa1ea5cf1dbea81af30b8ae7f6=600160035260406000604060006000731000000000000000000000000000000000000002620186a0f250600160035200 485db9468861ff56fb336a5a134619fe32ee06fe7753ce1dae5c6e7cd893a531=731000000000000000000000000000000000000000ff604060006040600073100000000000000000000000000000000000000361c350f400 540ce432b3faf56301cbb2a9c10c084662a44e8bfb4ed0f8fd05c63c3d4a61ee=604060006040600060007310000000000000000000000000000000000000016207a120f200 f0da9c01ce06dfb829b58182a0fb24e3568c3553534c74abb063a3e8832be49b=60406000604060007310000000000000000000000000000000000000016207a120f400 -b48d38f93eaa084033fc5970bf96e559c33c4cdc07d889ab00b4d63f9590739d=00 52c55979e5f38c43858a7b045adae78b14c7eb187eccd639c5925967fceefc7e=6040600060406000731000000000000000000000000000000000000001620f4240fa505860035500 -3d8f4bb3dad33ace4a8f7c6913646815b69d3c1f09dafd0d559582cec2d9d128=600160015260406000604060007310000000000000000000000000000000000000026203d090fa50600160015200 +b48d38f93eaa084033fc5970bf96e559c33c4cdc07d889ab00b4d63f9590739d=00 e466181d4de18c6565740a948ed375a7fe9891a0a75399242ff737c26a856b26=604060006040600073100000000000000000000000000000000000000162055730f4600055600160015500 +3d8f4bb3dad33ace4a8f7c6913646815b69d3c1f09dafd0d559582cec2d9d128=600160015260406000604060007310000000000000000000000000000000000000026203d090fa50600160015200 70e7b30188c10f3b74489ef379faa66340e65da8a80808b6c818c6822a8d1896=6040600060406000600173100000000000000000000000000000000000000162055730f2600055600160015500 c9e0efef6051a60fe41b11d60c4251dc7550f8130b97eab201a4722069a4fa0e=600160025500 6f2c9e67d2547208275b4ab871e237a4fa918163569ac8080ee96f1ca5caa8a3=6000356000526040600060406000731000000000000000000000000000000000000001620249f0f4600055600160015500 af8497642fe2691e45cea7806fb7b32ca3118f9f0b9ea95d1efea3333ec1dde4=6040600060406000600035614e34fa00 -36c09a0105dba101675477518b5de0f40ee543c20ebd216334a2136c0dd96bda=60016002526040600060406000600035614e34fa50600160205200 f5e209b303eade212f36f01b21e7b5a8ced3d863f2dca92d731ef404e65fb2d5=60003560005260406000604060006000731000000000000000000000000000000000000001620249f0f2600055600160015500 +36c09a0105dba101675477518b5de0f40ee543c20ebd216334a2136c0dd96bda=60016002526040600060406000600035614e34fa50600160205200 49a03e4a082ceed2f4d0ee0743159847cf4e90384f831ff9522dc5e54263f47a=604060006040600073100000000000000000000000000000000000000261c350fa50731000000000000000000000000000000000000000ff00 73b9beefffb6fc59d657c5cf1f65ad598588720d2293468e99ba84c0c199059a=604060006040600034731000000000000000000000000000000000000001620249f0f26000555a60015500 a4d8ac63bba5d1407cc90474aa760b25476191f9bfdb3ea3f205e30b83be56f7=6000356000526040600060406000731000000000000000000000000000000000000001620249f0f46000555a60015500 7cff0f681f55e309bc5b0b5558d7a0ea013598dae7dfe9d850a4aa2cdd29c9ba=604060006040600060003561c350fa50731000000000000000000000000000000000000000ff00 0f7018e4aefce00bec400639dbdeb88233c6c34d4173b8d0361ffc2848a818fe=600160015200 -56b70cdab35a44498f8c30f51b124841bcc612585f42bf683ed7139a989367a6=6040600060406000731000000000000000000000000000000000000002620493e0fa503360055200 7b74af78ab90454c7ba643be2a669f5126394b0bbd9aeafbd9c5d62a02968823=604060006040600073100000000000000000000000000000000000000162055730f4600055600160015500 +56b70cdab35a44498f8c30f51b124841bcc612585f42bf683ed7139a989367a6=6040600060406000731000000000000000000000000000000000000002620493e0fa503360055200 9369ca7656de8f96762b8b91431e9369c02656fd26053c627b454af8ceb9a4c1=60406000604060003473100000000000000000000000000000000000000162055730f2600055600160015500 9fa0d03017a2bcf1443caec9cf50043d73e5fd1740909380d1500bdae39b9aef=6000356000526040600060406000731000000000000000000000000000000000000002620186a0fa00 7ba813acda194fe4b62fee350fd3020f5c5b45160abcfb6e51889fcc8b37f9c1=600035600052604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 6c613adfea0dcd0824ed27114194787fcc267c40244035702c8f4715cea14784=6000356020526040600060406000731000000000000000000000000000000000000002620186a0fa50600160035200 510e52c221c015efc381ac34678af05fff9fbba15fecf7c3210fe7de502df981=6040600060406000602035614e34fa50600160035200 -d268180b298019481d7be10ba1cd08c80afc5214321ad815d093e9d5dad384ad=604060006040600073100000000000000000000000000000000000000262061ad0fa505b61c3506080511015603f5760013b506001608051016080526023565b00 -9f20298822a4958cf1dc738403369d631e04e8934953235e2344f9bdff9deec9=60406000604060003460003562092856f2600055600160015500 36820aea6f9402e8239f60a98c9450a4cf2b442a09539cb500a85e1506706b8b=60406000604060007310000000000000000000000000000000000000036201d4d4fa00 +9f20298822a4958cf1dc738403369d631e04e8934953235e2344f9bdff9deec9=60406000604060003460003562092856f2600055600160015500 +d268180b298019481d7be10ba1cd08c80afc5214321ad815d093e9d5dad384ad=604060006040600073100000000000000000000000000000000000000262061ad0fa505b61c3506080511015603f5760013b506001608051016080526023565b00 8b8fdfc6b0a8d4adef57eff09c997bcf3b5fb8cd1a189decbcd53fb9f7e3687c=60016003526040600060406000731000000000000000000000000000000000000003614e34fa50600160205200 -32e4d943aca0578baa32c4b55935067c1774d4b9796d92976c027dd5b1bd78ae=60016003526040600060406000731000000000000000000000000000000000000002619c90fa505b61c350608051101560435760013b506001608051016080526027565b00 f128aff3de450169fb369b813d485683dd3542f6beef48d4f8c12d7b0fb18212=604060006040600073100000000000000000000000000000000000000161eaf6f4600055600160015500 -614bcbeebf85626b016baa47ccb56a6ac8e749a7a3bc1e69503c60ea642d082a=6001600352604060006040600073100000000000000000000000000000000000000262061ad0fa505b61c350608051101560445760013b506001608051016080526028565b00 -de1bb63e65cd0796c21f393b4cc896526bb1fb32f87fe77995c7646757ee59f2=600160035260406000604060007310000000000000000000000000000000000000036201d4d4fa50600160035200 +32e4d943aca0578baa32c4b55935067c1774d4b9796d92976c027dd5b1bd78ae=60016003526040600060406000731000000000000000000000000000000000000002619c90fa505b61c350608051101560435760013b506001608051016080526027565b00 0f46598e2e1e8f98d1241e8eada22e112d94cfb3121a4c6ff54a674af11703ab=604060006040600073100000000000000000000000000000000000000162092d9cf4600055600160015500 +de1bb63e65cd0796c21f393b4cc896526bb1fb32f87fe77995c7646757ee59f2=600160035260406000604060007310000000000000000000000000000000000000036201d4d4fa50600160035200 +614bcbeebf85626b016baa47ccb56a6ac8e749a7a3bc1e69503c60ea642d082a=6001600352604060006040600073100000000000000000000000000000000000000262061ad0fa505b61c350608051101560445760013b506001608051016080526028565b00 0a907ef25f7ec3a7649fde0fc3bde1d5c600f6c6d3e0166d840549736ec07cd3=60406000604060003473100000000000000000000000000000000000000161eaf6f2600055600160015500 cd24eeb6ba19cd96b7c1843d903213377f400d5cd3a37704e5497c71a2ca035d=600035600052604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 +fbec71cba80e73df867097de0d4ee932071a8150cab693f5a7a93c089aaad60e=60016003556040600060406000731000000000000000000000000000000000000003614e34fa00 6ecb6187005c1b52d5b1b9c27a968488e5af836a2d06d8dec268f03faf4c064e=60016003526040600060406000600035619c90fa00 94249ff02157f717f6ea8ca94d3a8d7de38cbad39ec8293b7276d5d891f93b40=5b61c3506080511015601c5760013b506001608051016080526000565b6040600060406000731000000000000000000000000000000000000003614e34fa00 -fbec71cba80e73df867097de0d4ee932071a8150cab693f5a7a93c089aaad60e=60016003556040600060406000731000000000000000000000000000000000000003614e34fa00 +260f4e68033d4e00ac9ef749d006bf7415e8ff70b8d7c91edb81c19effae4f86=6000356000526040600060406000731000000000000000000000000000000000000001620249f0f4600055600160015500 350b386a63491778e8c5deba52e39331d598d4b288cf4c08991fa7b766d1e348=6040600060406000600035619c90fa50600160035200 1ca2139ddaff3045190c85c3f1a62f93cc328a8867c22e2d16974d051bc4dab4=5b61c3506080511015601c5760013b506001608051016080526000565b6040600060406000731000000000000000000000000000000000000003614e34fa00 a4c0ee0e96648cc50ca53228a42f432658166d070a9d4c149b902f04cf644363=60016003556040600060406000731000000000000000000000000000000000000003614e34fa50600160035200 -260f4e68033d4e00ac9ef749d006bf7415e8ff70b8d7c91edb81c19effae4f86=6000356000526040600060406000731000000000000000000000000000000000000001620249f0f4600055600160015500 -5ea8f924946ab1da886ea3d6fb342ad2f5ad281ba4daf64e0d54ea0756dfc5c5=6001600352604060006040600073100000000000000000000000000000000000000361c350fa50731000000000000000000000000000000000000001ff00 9e9ef6d05630957275c98645f1874d04a8386698f4b2e1c22ad2add17a3351da=60406000604060006000731000000000000000000000000000000000000001620249f0f2600055600160015500 +5ea8f924946ab1da886ea3d6fb342ad2f5ad281ba4daf64e0d54ea0756dfc5c5=6001600352604060006040600073100000000000000000000000000000000000000361c350fa50731000000000000000000000000000000000000001ff00 1e8f62ea8d62323b4facebd9a33309e6be110ab045c9068a124e0743ec7b8641=6040600060406000731000000000000000000000000000000000000001620249f0f4600055600160015500 23de4e424220ffefefb2130e496ec18b778b07e4554db256516c7bef0f969acc=604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 48133ce8c05d2a6ec8fbc4e23892bd5faf8bde675dd75064a8a3c04399e2506f=60016003526040600060406000731000000000000000000000000000000000000002620186a0fa50600160205200 -60ae939946e955ed64a55af1334be7353b16cf67154e6e993ec591dbce884498=60406000604060003473100000000000000000000000000000000000000163017d7840f2600055600160015500 3bc5208a1d4e38e24a6767941196cab880161d0f905b797d99e6280ff098613a=6040600060406000731000000000000000000000000000000000000002620f4240fa00 +60ae939946e955ed64a55af1334be7353b16cf67154e6e993ec591dbce884498=60406000604060003473100000000000000000000000000000000000000163017d7840f2600055600160015500 91a0e84c1e91aae18f142ce0292dfeb6a10163f366259318b8a919f9d414d737=604060006040600073100000000000000000000000000000000000000163017d7840f4600055600160015500 58602048e23c946475e99fcb483028b9f4b93d658d602acfc604a7b360d609ff=600160015260406000604060007310000000000000000000000000000000000000036203d090f4506001601f5200 5cb3d491a0a70a0af216a87e20fbe23ba17785d85118fdd5814c750419546197=60016001526040600060406000731000000000000000000000000000000000000002620493e0fa506001601f5200 -4bd54fc1246bc6cdda8054b1736ad1647804b383d908d028d6018dc61eea02aa=6040600060406000600035620493e0fa00 84d1af0c5c6c3883b3c16560eac3756318e4115fb14bdda65e718ef213c984b5=60003560005260406000604060003473100000000000000000000000000000000000000162055730f2600055600160015500 +4bd54fc1246bc6cdda8054b1736ad1647804b383d908d028d6018dc61eea02aa=6040600060406000600035620493e0fa00 1011b3270837b0bc4fbf6531f8ce57306e94efd1d9e5d3c841d40e613e60ef14=60406000604060007310000000000000000000000000000000000000036201d4d4f400 4371bec7904154375251cdb8ad720246cda44afd4265f54a97fdb17f8593f08d=604060006040600073100000000000000000000000000000000000000262030d40fa00 756d7e76b15eda302bd0da29fe9670240105b4d434b6785ad9830bc2a7c9794c=600160035260406000604060006000731000000000000000000000000000000000000003614e34f200 -28e88bc8516f4edf414d22533479b4b26a559189c25a285e2f2bd546c93d0045=604060006040600060007320000000000000000000000000000000000000036201d4d4f250600160035200 -6ac0a7431d0eb3e895d3c0fadeab35226f85930c46eb9bba91d8220f2d2401ad=604060006040600060007310000000000000000000000000000000000000036201d4d4f250600160035200 06fb81d18433dc0ded42d33d4464632d084b7c904e5aec9ce159f8e303bf7637=604060006040600073200000000000000000000000000000000000000262061ad0fa50600160035200 -71dbc3fca2af095c1853e6d45c001c84a647976dab0596259de5ab597a35118b=60406000604060006000732000000000000000000000000000000000000001620aaef6f250600160035200 +6ac0a7431d0eb3e895d3c0fadeab35226f85930c46eb9bba91d8220f2d2401ad=604060006040600060007310000000000000000000000000000000000000036201d4d4f250600160035200 +28e88bc8516f4edf414d22533479b4b26a559189c25a285e2f2bd546c93d0045=604060006040600060007320000000000000000000000000000000000000036201d4d4f250600160035200 da8d5432a874207132bcf3abde03605d022c018ebe7400d7875aaec2c4c00407=60406000604060006000731000000000000000000000000000000000000001620aaef6f250600160035200 -53ea926755491ecc957290dc5b2761ae0556232b03dc5471fbc718d9c844bd23=6040600060406000732000000000000000000000000000000000000003614e34f450600160035200 +71dbc3fca2af095c1853e6d45c001c84a647976dab0596259de5ab597a35118b=60406000604060006000732000000000000000000000000000000000000001620aaef6f250600160035200 +52c50940cc34283081c291b8240f2efe9a017c174c698ad7a1751209c8b58a4f=6040600060406000731000000000000000000000000000000000000002619c90fa505b61c3506080511015603e5760013b506001608051016080526022565b00 7ed1a2b2d590a12d61621ac6a7349a10a5571af1ec032ee3726de3887f6ed2e3=6040600060406000732000000000000000000000000000000000000002619c90fa00 0b3c9a8f6810a7d891a1b98f1e626517238a509f4e58a4a6ab122d81f700671b=604060006040600073100000000000000000000000000000000000000161eaf6f46000555a60015500 -52c50940cc34283081c291b8240f2efe9a017c174c698ad7a1751209c8b58a4f=6040600060406000731000000000000000000000000000000000000002619c90fa505b61c3506080511015603e5760013b506001608051016080526022565b00 -b29eebdd30e390867117f875b426663efcc56c2e1ca53e008100448daf179444=604060006040600073200000000000000000000000000000000000000161eaf6f4600055600160015500 cb76cadcc46d52fe0db8a30112e78c679fa3ca3ea5ae25a1f53a5211c45302d8=6040600060406000731000000000000000000000000000000000000003614e34f450600160035200 +53ea926755491ecc957290dc5b2761ae0556232b03dc5471fbc718d9c844bd23=6040600060406000732000000000000000000000000000000000000003614e34f450600160035200 +b29eebdd30e390867117f875b426663efcc56c2e1ca53e008100448daf179444=604060006040600073200000000000000000000000000000000000000161eaf6f4600055600160015500 +8a2731d929b54f34dc0b82265e6bb2dc91bd33c186789d5e93bc8110fad0b0ea=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060006000731000000000000000000000000000000000000003614e34f200 b7163a865729b62df082e1b4f8e8bfd1f19244f9a5341116011ddf5abb4dfa28=604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 a2a239813865d7d5692bb2207007a923a27c7aad842251e6e6528820df5d2be4=60016003526040600060406000731000000000000000000000000000000000000002619c90fa50600160035200 -8a2731d929b54f34dc0b82265e6bb2dc91bd33c186789d5e93bc8110fad0b0ea=5b61c3506080511015601c5760013b506001608051016080526000565b60406000604060006000731000000000000000000000000000000000000003614e34f200 707f41cf7885b5ead8e3e1ba796b727b8e466875ffba6fae98a52ed932a0c1ca=5b61c3506080511015601c5760013b506001608051016080526000565b6040600060406000731000000000000000000000000000000000000003614e34f400 2091a5db3247f6d174ad7a3becf4ffcefa1171720288653cd7e80c980fe255c4=731000000000000000000000000000000000000000ff6040600060406000600073100000000000000000000000000000000000000361c350f200 +fef2ad1bd1d0042a6efdd15783014b1af38d0e62db2d9b3f4dcb95a4102aa1f9=60406000604060003460003563017d7840f2600055600160015500 8e91a8556ca4ea7ca6e52b6207def03bc8dec91c4122be6b66bc215c78aa265c=6040600060406000732000000000000000000000000000000000000002620f4240fa00 18e71aba1fabecef860a76d397205a6226dd73c289caaa59e237037cdf3f33e4=604060006040600060017320000000000000000000000000000000000000016207a120f200 -fef2ad1bd1d0042a6efdd15783014b1af38d0e62db2d9b3f4dcb95a4102aa1f9=60406000604060003460003563017d7840f2600055600160015500 -cafe4006fa0a33e7beb1bb618c22ee3c36be51c9b437d2eb77e10ca1db33ed20=60406000604060003473100000000000000000000000000000000000000162055730f2600055600160015500 b98a2cd25451cc59f3e145e18b860744e8a92d1c6afbc521919947b15a198ba6=604060006040600060013403731000000000000000000000000000000000000002620493e0f200 +cafe4006fa0a33e7beb1bb618c22ee3c36be51c9b437d2eb77e10ca1db33ed20=60406000604060003473100000000000000000000000000000000000000162055730f2600055600160015500 07f6a9472c712464919f59e9e8785a2c8972273b04f2370fc1e4931e65430371=600160015260406000604060007310000000000000000000000000000000000000036203d090fa50600160015200 -c68361add39b3ac30cfe63fdc345f2e0712b8194b1653a6df786532ee0dfefb2=600160015260406000604060007310000000000000000000000000000000000000036203d090fa506001601f5200 1918a8f94735cfee2a5bd6f836f14eb12f7f43faa317b3d84aea67c96f5c2774=6001600152604060006040600060013403731000000000000000000000000000000000000002620493e0f2506001601f5200 -0bf40b092409d33068ede1528ed0c7589021e8e292d7dfdd15f144755b49cff9=6040600060406000731000000000000000000000000000000000000003614e34fa00 +c68361add39b3ac30cfe63fdc345f2e0712b8194b1653a6df786532ee0dfefb2=600160015260406000604060007310000000000000000000000000000000000000036203d090fa506001601f5200 b6e6ebdd00d58b886b5d2c7c7318961b0defdd3a3c94852c1a62d6560ed9bfaa=604060006040600060013403731000000000000000000000000000000000000002620186a0f200 +0bf40b092409d33068ede1528ed0c7589021e8e292d7dfdd15f144755b49cff9=6040600060406000731000000000000000000000000000000000000003614e34fa00 a06aee939887e976a9ed735d040644f23e196c0b66bae5072e0251081b4bd3e4=604060006040600060013403731000000000000000000000000000000000000002619c90f2505b61c350608051101560425760013b506001608051016080526026565b00 -377901720af802d93c9a67ccfa9732ce496dc57a5bc06dcace058ef7bb0dc21e=6040600060406000731000000000000000000000000000000000000002619c90f4505b61c3506080511015603e5760013b506001608051016080526022565b00 9997b6fb70eb91d61dbd8d5e51e1fb06152afe9d045bd279766b8e557dadcfd9=6040600060406000731000000000000000000000000000000000000003614e34fa00 -22109675dc763fc2ff376e0489170c411a5be253e37c288fccffea224388d22e=604060006040600060013403731000000000000000000000000000000000000002619c90f2505b61c350608051101560425760013b506001608051016080526026565b00 +377901720af802d93c9a67ccfa9732ce496dc57a5bc06dcace058ef7bb0dc21e=6040600060406000731000000000000000000000000000000000000002619c90f4505b61c3506080511015603e5760013b506001608051016080526022565b00 66fd6efff22789e0022a148c485bcc4dd430c75c87a5ac0ddc84a4978d334d10=60406000604060003473100000000000000000000000000000000000000161eaf6f2600055600160015500 +22109675dc763fc2ff376e0489170c411a5be253e37c288fccffea224388d22e=604060006040600060013403731000000000000000000000000000000000000002619c90f2505b61c350608051101560425760013b506001608051016080526026565b00 fc5309d4154da6030e05a30dd2ce4585118873591176f79ee402988d43297b24=604060006040600034731000000000000000000000000000000000000001620249f0f2600055600160015500 6bf73fe3b9e1007d402594ae2d1ea36fb201eb90c7f68d788d81d2159cfaf582=604060006040600060013403731000000000000000000000000000000000000002619c90f200 4a20daf1922ebcc25cf82baf42ee2c532c2da74926e44894a7c7e8770abc7d81=6040600060406000731000000000000000000000000000000000000002619c90f400 @@ -2795,31 +2770,58 @@ fc5309d4154da6030e05a30dd2ce4585118873591176f79ee402988d43297b24=604060006040600 21906a140b3d2329b1b977c9bdb906d61e092ce21f8f3644ea709b839e462ec4=6040600060406000731000000000000000000000000000000000000001620249f0f46000555a60015500 af9837019dc7e71ad40ad889121d58d8840f03364cfa98c910fea95cebe565e0=6040600060406000731000000000000000000000000000000000000002620186a0fa00 f6f3d117f582e9aeed2b021271206d10bb0d1122bcd53be6f33273d5d05b2852=60406000604060007310000000000000000000000000000000000000026203d090f400 -6aaee305608773195015611678fc4b42bd9996507fffbd7646555c815b32c8ae=600160015200 -f49691185c98bc4d38cbd6f72fee8d284ae0347ac3dab980fe98fc9855053d08=60006000600060006000734000000000000000000000000000000000000004620f4240f200 ca395fbb13fec43e41a6f1dd5f292ebd9f3ba198b79e4caf0ea84aaac1116d27=604060006040600073100000000000000000000000000000000000000161c350fa00 +f49691185c98bc4d38cbd6f72fee8d284ae0347ac3dab980fe98fc9855053d08=60006000600060006000734000000000000000000000000000000000000004620f4240f200 +6aaee305608773195015611678fc4b42bd9996507fffbd7646555c815b32c8ae=600160015200 d5680d1a57d65009464d64daf8a18d829b4321d52250ba8252efb41dfe013548=600060006000600060007340000000000000000000000000000000000000046103e8f200 b6854de517529726bb59d586b298c37c964c0bea333f2ae471b44beb4a230ed8=6000600060006000730f572e5295c57f15886f9b263e2f6d2d6c7b5ec66103e8fa600055600160015500 6c0e2b5b332daee1e973fdc64c85c26e3ba3989a858fa1c32cc57423045be2e6=6000600060006000730f572e5295c57f15886f9b263e2f6d2d6c7b5ec66103e8fa60005500 +62ba2266bc159fa76122f6b060114940d17c4dcce9cdf5e4fb75cd475ceb7df3=60ff6000533360006000600060206000a400 318aa00ff7c3c999aec760237f43b8a15e0c221498a327b4eaf57003b2afc156=60ff6000533360206000a100 cfc2b962815c543844b7b2a412adbe303fa0efa9a2e0ec93c1fbf9e231558199=60ff60005360206000a000 -62ba2266bc159fa76122f6b060114940d17c4dcce9cdf5e4fb75cd475ceb7df3=60ff6000533360006000600060206000a400 66ea953d8c72d0637943560c649fb4f6d540ad3cdacebd34ba592c612cdefc72=7b601080600c6000396000f20060003554156009570060203560003555600052600060006000600073aaaaaaaaace5edbc8e2a8697c15331677e6ebf0b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecfa00 5eff31ebea62b04f764a877c84c2cc92a00a13feff33ed56c575a25635dab23d=600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa61157cfa600055600160015500 2c7538956a539ad4d8bdba9d385d2d6e7eb6f48132f53904a872aace872a4831=600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa600035fa600055600160025500 4772f5788435b31f3f8113b688d52e50ee0aa6e7de5a5ecabab787114ea75a8d=600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa600035fa6000556000600060006000600073aaae7baea6a6c7c4c2dfeb977efac326af552aaa600035f100 -f26b0805bac34e43cbe429c9f772f7113748e7bfeca8e39df096ed3d0552c258=6000600060006000601773095e7baea6a6c7c4c2dfeb977efac326af552d8761c350f1600101585500 +84e732055591f479202856ec8f623d1e658edaf7d7809222327ed8e5ffe654fa=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed6000556000356000526000600060206000600073a0000000000000000000000000000000000000005af16001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +c95eb6147c609e08130642304cc51ae275b0e820a9977983a272b34c54c78e00=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60005560006000600060006000355afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +9ea036a2ecc2d488c43c1c709066fe7c2b4a08bb40ab95a86e2a8a6c5b4c01c0=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602061200060806000600260015af100 +ad49657ad70b902dd9b0677d5b7833b0f0e83588e6cfc455a1ac9917129eb1bf=7c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600260025af100 +eb5eb639416472e142020f1e67a041cfcaf8d03a842f9c01bd89597085049d75=7c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600260035af100 +8229242bf1fde9040f2f396ee2a1b987438811e5e5005cbcab281d5041a4c962=7c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600260045af100 +7426d3b5746a93100d741da990638c6b7f7cf02a67dab9a69a0f7cf09a0928c7=6001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a052602061200060a16000600260055af100 +cd6179f0a65f4246fd10b7212d395502415ca6076ea088ea3c8e94c1707b9fe7=7f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d4606052604061200060806000600260065af100 +a5fd552973e23abd9024bf8412ce25ae9c29d970146f929cb0cad298a8f29615=7f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020526003604052604061200060606000600260075af100 +112917d8c4616c52b1409fa4c4b68f40c0d692d46980d727901a158c458ad973=7f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206120006101806000600260085af100 +8f1154bfbac5fd067c557a227185f40ffcce358aafb06e90bec9c0aeb7474a99=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed6000553660006000373660006000f06001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +0a614964c672e15a4d50346ccbbd43debd239d03dec56e7daccd06a2d430e928=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110010000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +bd8e9570497da58a1e7a4fceec87eae435f91aaa48ecea0936bad917aba5d805=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110020000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +b1a5e754bbbd98759d83a64057317f6e3bf4755539a0de0d2d01bb68c456a1ba=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110030000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +b4d2be0cfe7c0fd138fc1a307c2d7a20d3a6f7cf908b3257c1e3077a9e969dc5=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110040000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +8dbbdbafb844667151cad451f4da1f4ac1e3e6b20f6ae17b890d2d68ec73e389=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110050000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +cd3b6dabee431709fc2561e4888c5169939a38419d4a3205044e82be5a053ef6=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110060000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +70b83ebf52c9d6bde3d6afa24d3d2b480bad4c62a10037f3950f09cf70c19edd=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110070000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +feb32c5cc73e034f2e04193cd35fb6157ec84745bdf2b01d3708437922053865=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110080000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +4b8086243146fa9008248cd0d1a2bc488005f32f793f25a31c159a93bb514f37=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed6000556000600060006000600073b0000000000000000000000000000000000000005af1507ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60015500 +a7b95cbf5827efe70bc6de71fadd07cec971227e581dce759a09b6343a722828=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60005562012020620a00006000600073a0000000000000000000000000000000000000005afa507ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600155620a000051610a0055620a110051610a1155620a010051610a0155620a120051610a1255620a020051610a0255620a130051610a1355620a030051610a0355620a140051610a1455620a040051610a0455620a150051610a1555620a050051610a0555620a160051610a1655620a060051610a0655620a170051610a1755620a070051610a0755620a180051610a1855620a080051610a0855620a190051610a1955620a090051610a0955620a200051610a2055620a100051610a105500 +3be0f9628c2a23d54ff633103257d0defddee2a78dac6362694a32ae88524c1e=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602061200060806000600060015af1620a00005260a060020a6120005106620a010052620a0100513214620a02005260006000526000602052600060405260006060526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060025af1620a030052600051620a04005261200051620a05005260006000526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060035af1620a060052600051620a07005261200051620a08005260006000526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060045af1620a09005261200051620a10005260006000526000612000526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a052602061200060a16000600060055af1620a11005261200051620a12005260006000526000602052600060405260006060526000608052600060a0526000612000527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d4606052604061200060806000600060065af1620a13005261200051620a14005261202051620a15005260006000526000602052600060405260006060526000612000526000612020527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020526003604052604061200060606000600060075af1620a16005261200051620a17005261202051620a1800526000600052600060205260006040526000612000526000612020527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206120006101806000600060085af1620a19005261200051620a20005260006120005262012020620a0000f300 +96d286f562b996dce5062cad0a9c13b57edc86ac8505797641f7e1e76fd3eb93=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055366000600037655a175a175a173660006000f56001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +d9ee1ed86455c4d7ca5c8734f327a0cd55d4b62cf74dc98cc5bda96e1bd7d4fe=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60005562012020620a00006000600073a0000000000000000000000000000000000000005afa507ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600155620a000051610a0055620b000051610b0055620a010051610a0155620b010051610b0155620a020051610a0255620b020051610b0255620a030051610a0355620b030051610b0355620a040051610a0455620b040051610b0455620a050051610a0555620b050051610b0555620a060051610a0655620b060051610b0655620a070051610a0755620b070051610b0755620a080051610a0855620b080051610b0855620a090051610a0955620b090051610b0955620a100051610a1055620b100051610b1055620a110051610a1155620b110051610b1155620a120051610a1255620b120051610b1255620a130051610a1355620b130051610b1355620a140051610a1455620b140051610b1455620a150051610a1555620b150051610b1555620a160051610a1655620b160051610b1655620a170051610a1755620b170051610b1755620a180051610a1855620b180051610b1855620a190051610a1955620b190051610b1955620a200051610a2055620b200051610b205500 +0234fd7879d6486d237da0c6030340a887a320ad8d126a6daf76c9ba5611f6c5=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549606052602061200060806000600060015af2620a00005260a060020a6120005106620a010052620a0100513214620a020052600061200052602061202060806000600160015af2620b00005260a060020a6120205106620b010052620b0100513214620b02005260006000526000602052600060405260006060526000612020527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060025af2620a030052600051620a04005261200051620a050052600061200052602061202060206000600160025af2620b030052600051620b04005261202051620b05005260006000526000612020527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060035af2620a060052600051620a07005261200051620a080052600061200052602061202060206000600160035af2620b060052600051620b07005261202051620b08005260006000526000612020527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc000000600052602061200060206000600060045af2620a09005261200051620a100052600061200052602061202060206000600160045af2620b09005261202051620b10005260006000526000612020526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a052602061200060a16000600060055af2620a11005261200051620a120052600061200052602061202060a16000600160055af2620b11005261202051620b12005260006000526000602052600060405260006060526000608052600060a0526000612020527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d4606052604061200060806000600060065af2620a13005261200051620a14005261202051620a150052600061200052600061202052604061300060806000600160065af2620b13005261300051620b14005261302051620b15005260006000526000602052600060405260006060526000613000526000613020527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020526003604052604061200060606000600060075af2620a16005261200051620a17005261202051620a180052600061200052600061202052604061300060606000600160075af2620b16005261300051620b17005261302051620b1800526000600052600060205260006040526000613000526000613020527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206120006101806000600060085af2620a19005261200051620a20005260006120005260206120206101806000600160085af2620b19005261202051620b20005260006120205262012020620a0000f300 +9a1120d19b7b2d1202e5a11ef1f37a1929c670177e16beaf188df19cfc106570=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055366000600037635a175a173660006000f56001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 +0ffa096238cc2e0df9e4cde0ef0b7a82a0362a1ce80056ab959597e365da4fd0=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206120006080600060015af4620a00005260a060020a6120005106620a010052620a0100513214620a02005260006000526000602052600060405260006060526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206120006020600060025af4620a030052600051620a04005261200051620a05005260006000526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206120006020600060035af4620a060052600051620a07005261200051620a08005260006000526000612000527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206120006020600060045af4620a09005261200051620a10005260006000526000612000526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a052602061200060a1600060055af4620a11005261200051620a12005260006000526000602052600060405260006060526000608052600060a0526000612000527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d460605260406120006080600060065af4620a13005261200051620a14005261202051620a15005260006000526000602052600060405260006060526000612000526000612020527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba602052600360405260406120006060600060075af4620a16005261200051620a17005261202051620a1800526000600052600060205260006040526000612000526000612020527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa610160526020612000610180600060085af4620a19005261200051620a20005260006120005262012020620a0000f300 575b2924d21dbc04f3c7fd67001d835f61f6939764bc8ee4538e7394fa400012=6000600060006000601873945304eb96065b2a98b57a48a06ae28d285a71b5620186a0f1585500 -b94850406c5cc6921a6e6d8bde93b0f1e88973724fdc618631232ec443ff5691=6000600060006000601873945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03f1585500 +f26b0805bac34e43cbe429c9f772f7113748e7bfeca8e39df096ed3d0552c258=6000600060006000601773095e7baea6a6c7c4c2dfeb977efac326af552d8761c350f1600101585500 ecdbcebf816bd6ffd6e9da9d9307cdd607cc57071f27d857549d810d733fd2bf=6000600060006000601773095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03f1600101585500 -1e6a612423b1c661aecfd0d91d2339e425f91dcff078cd9d07d28c405e8bc1a6=6001600054016000556000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03f100 +b94850406c5cc6921a6e6d8bde93b0f1e88973724fdc618631232ec443ff5691=6000600060006000601873945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03f1585500 cf5fd0ebd61fc2dbf8dac98eabdc6b44980e07c42b6814dec77a941628bae32a=6001600054016000556000600060006000600173945304eb96065b2a98b57a48a06ae28d285a71b5620186a05a03f100 +1e6a612423b1c661aecfd0d91d2339e425f91dcff078cd9d07d28c405e8bc1a6=6001600054016000556000600060006000600073095e7baea6a6c7c4c2dfeb977efac326af552d87620186a05a03f100 b254f222c66920f0da84e3e5327cdb7a4a78e48aed4cf079f517be94be4c13bb=6000600060006000601873945304eb96065b2a98b57a48a06ae28d285a71b5620186a0f1585573945304eb96065b2a98b57a48a06ae28d285a71b5ff00 -f2a018a1727b04c0eed1e47c656aa734465df019c4e6cc6761d1fc43c4272558=6000356000526000600060206000601873945304eb96065b2a98b57a48a06ae28d285a71b5600035f1585500 86e091a7ccdb683bac5489b99bd742053ecee5874f04a78561b6197ee5082b85=6000356000526000600060206000601773095e7baea6a6c7c4c2dfeb977efac326af552d8761c35060003503f16001015855730f572e5295c57f15886f9b263e2f6d2d6c7b5ec6ff00 +f2a018a1727b04c0eed1e47c656aa734465df019c4e6cc6761d1fc43c4272558=6000356000526000600060206000601873945304eb96065b2a98b57a48a06ae28d285a71b5600035f1585500 78aa31217c88bb237260ad76d5e7b1e9466a0b5bd65e1a4e254e06f58d86991d=5b600a60805110156042576000600061c3506000600173aaaf5374fce5edbc8e2a8697c15331677e6ebf0b650ffffffffffff16000556001608051016080526000565b60805160015500 -7e3b8f4e80ca8679786483f27f64ac780f82e72385fbc89b420027cc437eea9f=6001600054016000556000600060006000600030612af85a03f160015500 fa24c7c55f747597fc149cce83a02d9843f9e1dbf982d5f75e1111da358547da=6000600060006000601773945304eb96065b2a98b57a48a06ae28d285a71b56305f5e100f100 +7e3b8f4e80ca8679786483f27f64ac780f82e72385fbc89b420027cc437eea9f=6001600054016000556000600060006000600030612af85a03f160015500 97acd9b2ba21ee05bf3ac6c3a1f535f821b539c64a02322f2d71e2ade8a1fe1c=600160005401600055690fffffffffffffffffff610402600054040260025560006000690fffffffffffffffffff610402600054040260006000306104005a03f160015500 4e009047ee5311748b376c8542e67a3a2fc308addd07cc27c90724ba32b5e38d=6001600054016000556000600060006000600030613a985a03f160015500 faf42407d80f6f38660d94fbb71f781655060e1300aa15a3c783a67c0a646b7a=600160005401600055600060006000600060003060e05a03f160015500 @@ -2866,26 +2868,19 @@ ab5b917d75aac5d962a3168efd6ead120cc02e6ec06ee5242ba71114defb0f87=3360005574a94f5 8f24d063903320c0f6c943d25de98e81b372e1f3ce8020082ccedd822488ebdd=73aa1722f3947def4cf144679da39c4c32bdc35681ff00 550609379228a503286becbdac3f11f0e8c34a87f319f1c9f42e72915a020eb8=3260005532ff00 e4f1b2898fa0df55ee71f5a079c79ff85bba1b6a3c3ac07a490f31b67654832a=30ff00 -6315c89fa4d6e5deee0e07defb2e2066977c3c91c59b27d7bf8c141a28b76ac8=60006000556001600155600260025500 -703d0c15eeb85de5eed825f12952dbe8012c0b3c0c5a3c6c4896b4fc5eed3f1c=60206000fd00 -c7c9e0d50668312cc59dcf39ed5ef85996be9f115827f64ad762c494ac87fb45=5b61c3506080511015602b576000600061c3506000600262013178fa6000556001608051016080526000565b60805160015500 -ef05bea5645aa48c5e7325bb1a23119c961290af1c112594ee1aa06e054277db=5b61c3506080511015602b576000600061c3506000600262013178fa6000526001608051016080526000565b60805160205200 e2998c7c4d3ffd69ed0b70cd030a0f892f2f04f0a2c6661478e1f3f0ab38bedd=600060005560006001556000600255600060035560006004556000600555600060065560006007556000600855600c60095500 80d63b6cef9d82595d5207a27429938ccf744601458c5e7268d6f43549b3aef4=64600c6000556000526005601b6000f000 -916769d38ed309a283d0639b202170e9b778dec4b23401b7f737e8259e6cf454=6000600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b6161a8f100 b5449ad280d4b54db0bd0d5b109c28f7ddab926a8fb168387c423352e8733907=603760015500 +916769d38ed309a283d0639b202170e9b778dec4b23401b7f737e8259e6cf454=6000600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b6161a8f100 2c1a699913984bf25854461c0a2fcf852759e7fdeb5bfbc959305b64f8245eb6=6000600060006000600173c94f5374fce5edbc8e2a8697c15331677e6ebf0b611388f100 39dc286827f4e11b0c27330b0399837d618c349d58bc7d032fc8beddb9b24eae=600060006000600060016000619c40f100 0819cb021f81370dc3d7d14a3fa84fce82d9db2e5264e0fce4f5bc28b89dd744=600060006000600060016000620186a0f100 -a1897b85f45fda57e0a6a0392ee937faca85ac4f2cf19ce64299c643adc4697d=6001600055 -c0dd80915f83ad0c28b39bd774f7e0181f5f816f8c3a48f144def017bc8f6323=600080600080600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f150 -96a9947f0caa33cf940a613503fcd235fd81c79d31934738811490108abc6dc1=600080600080600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f150fe -599b5e3571250b191031cd230cd4def7ce14c834b796dddd48d69c8d7cd510ff=600080600080600073b94f5374fce5edbc8e2a8697c15331677e6ebf0b61c350f15060ef60005360016000f3 +2a203f69a317afd0cdf2dd1ca84a097da8a0cdda385e87a53540eee36596e3b3=7f6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9600052601b6020527f79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817986040527f6b8d2c81b11b2d699528dde488dbdf2f94293d0d33c32e347f255fa4a6c1f0a9606052602060006080600060006001620f4240f1600055600051600155 9c3d4d32bdfbe6aba7805fac561682e706c6fe15490dd10a81f815ab1c72ddab=6000600055600060015560006002556000600355600060006000600060016000614e20f100 f3377e9d4f09b635d56a8f2920cb572f927692b5c7d275e0011a9f054139d298=600060005560006001556000600255600060035560006000600060006001600061c350f100 e3669f5ce010826e278e252dec1f74ceb2e71ed12270a062ed4de187ea78e719=635a60fd556000526004601c6000f000 -94dbd8dbb7085e6bcb88b8be8b99cc70470085eb68d1b80dfcb78b8fa9a713a8=6001ff00 21bf113995efc70852a2c4e35595a6f277fa46118386eecd47fa077730ca3cd1=6000600060006000600060006000f1506000ff00 +94dbd8dbb7085e6bcb88b8be8b99cc70470085eb68d1b80dfcb78b8fa9a713a8=6001ff00 9154fb82afafc124f4eb1ba75102f69e51a2957e3b3a6bd4ed421173a1a57a11=6000600060006000600160006000f1506000ff00 82f8a4223d0dc45259ee5caeed7281a789472a29852447a1e2c71cf502603732=6000600060006000600160006155f0f1506000ff00 038c2a3bbbd6ae23c6b7c6aa9f7ce434bd6eb3c54d9d1066c8af7d4d3470ae5c=600060006000600060016000600035f1506000ff00 @@ -2901,142 +2896,3 @@ c4bf5ad3a96e11d4a794acd75d486639b5cf225f871db8d20d56123b23f526d4=600060006000600 d8a56c290ee5169eb894f0fa07066821d23f5f3d40b071d6e0d6c7afb282fe37=5a6000556000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f2600155600160645500 abd7afc4a0b5580e7dc271b92f328b8e6996a971d6cf6612cb392fa447f2709f=5a6000556000600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f1600155600160645500 9555f80f23ad28f27a451dcf714ba3ca9508c507d16c2f5c74f9e9d991b51ec2=5a600055600060006000600073c94f5374fce5edbc8e2a8697c15331677e6ebf0b61ea60f4600155600160645500 -887ff804cc222e9826cbcd8677ca4ef2fd052f509a80bfe6ef26438fcb950234=60203560205260403560405260603560605260803560805260a03560a05260c03560c05260e03560e052610100356101005261012035610120526101403561014052610160356101605261018035610180526101a0356101a0526101c0356101c0526101e0356101e052610200356102005261022035610220526102403561024052610260356102605261028035610280526102a0356102a0526102c0356102c0526102e0356102e05260206103e86000356020600060086207a120f26000556103e85160015500 -eef1da772272a92701c8f29800159b8fde940b5a8f44e9cce3e3350ae15ee262=60003560005260203560205260403560405260603560605260406103e86080600060006006624c4b40f26000556103e8516001556104085160025500 -89c65a3b8fb53dd3d61963bffebdd8ea1c1c927edf686edfd7282749e8059bfa=6000356000526020356020527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000060405260406103e86060600060006007624c4b40f26000556103e8516001556104085160025500 -9b749abcee359228b8cfb285d71bcfc0ea6cf1ad37494486d2f18ba33ffb1d0f=600035600052602035602052604035604052606035606052604060c860806000600060066207a120f260005560c85160015560e85160025500 -3c711b94a887bc5af4ffb282942c8c90639ce92580ad594a43f9c9b04dbf106a=600035600052602035602052604035604052606035606052604060c860406000600060066207a120f260005560c85160015560e85160025500 -8120c3249700223e4b8c858e23cc99d319ffa988d733174af173d3f80fa17c0f=60003560005260203560205260403560405260603560605260803560805260a03560a05260c03560c052604061012c60806000600060066207a120f2600055604061019060606080600060076207a120f260015561012c51600a5561014c51600b55610190516014556101b051601555601454600a5414600255601554600b541460035500 -29f6accc6202a4e25f6d2d833cc6f34db0d0001a6968076f8ea6cf02350f0acd=3031471460115500 -d43c00d48b1c1ffcedb3490a446d91d3772d90549829fea32dbd1cec66a10c6b=60006080525b608051541560755760003560011415602c57600060006000600060006080515460155a03f1505b6000356002141560495760006000600060006080515460155a03f4505b60003560031415606857600060006000600060006080515460155a03f2505b6001608051016080526005565b00 -71891782a36768b68f09d49991e9e9b72f8555e2be3ce293dd936cb9bc1b33da=6000600060006000600073b000000000000000000000000000000000000000620493e0f1506000600060006000600073dea0000000000000000000000000000000000000620927c0f100 -e099d68aa4f2daf6478c3bc0b7548c9734e931aadbb11b30f05e237e99d75350=6000600060006000600073b000000000000000000000000000000000000000620493e0f2506000600060006000600073dea0000000000000000000000000000000000000620927c0f100 -9f6d79f8482e993b5f25658c889c2d4430fd144199b705155d6498c170a3d052=600060006000600073b000000000000000000000000000000000000000620493e0f4506000600060006000600073dea0000000000000000000000000000000000000620927c0f100 -1746fa5b8f53d54e021c7806e3ae5e395815d7fb52f8b33663236036207faf6f=600060006000600073c000000000000000000000000000000000000000620493e0fa506000600060006000600073dea0000000000000000000000000000000000000620927c0f100 -e1fa97c83a54f7f4e0aabb2042a916f2fe4033367580da4a417a21cae4944780=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600260005560026000556001600055600160015500 -25545ad8736b4da3db816ca115b8fdf0dcd889666ce9d209775c077fa4d4120e=6000600060006000600073b000000000000000000000000000000000000000620493e0f1506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd00 -55a9d8460b24e3d0227c9422a735e4870105a67dd2958c143572e2d040019ae1=6000600060006000600073b000000000000000000000000000000000000000620493e0f2506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd00 -6deee4808eec3bae38b305056e5b4f469806f187c2c9b7e56199dfa9bdfb4ab7=600060006000600073b000000000000000000000000000000000000000620493e0f4506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd00 -2b4378966c91379f6ee0b221c36b8f7c299bb6d00ca8e45cb67a981f2b9f546d=600060006000600073c000000000000000000000000000000000000000620493e0fa506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd00 -304d5614aa002d9edbae78d6be955868f32d371d6476a45dc7a6fdd0a2e36da7=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600260005560026000556001600055600160015500 -a26bb885494e0b85f27e61d59f8f645aeaea0a42b03b4d6f2c9e327989f55816=38600155303b60025500 -0cb7ff2ff5e91cde9ae944d1e97fbd4ba7846b22dd7870a48acde18e2116d79c=626001ff60005260006003601d6000f500 -fe0da0e6c1a27cd3fcd9449de9c3fc8ae987439af42de55d589e07dbe20b53a6=6b626001ff6000526003601df36000526000600c60146000f55060006000600060006000735649527a8464a86cae579719d347065f6eb27279620249f0f100 -9156fae8844f012720eec7d8aa673ad9cca3ca5dd23b928b9775b0cba8e970d0=626001ff60005260006003601d6001f500 -baab856cbce79430fa7358b1627a07ba23e047dc1feb2393baff5d6ddc6a7b9d=6b626001ff6000526003601df36000526000600c60146001f55060006000600060006000735649527a8464a86cae579719d347065f6eb27279620249f0f100 -4f730cbed6ba69e54f7096c4556fd45f9e40f12e9b3cb3ffa65ad569985cb51b=6130ff60005260006002601e6000f500 -163dc9fb46fc6db079e9223926481815c207e8d87b5b4f57a209439734a34568=6a6130ff6000526002601ef36000526000600b60156000f55060006000600060006000736cd0e5133771823da00d4cb545ec8cdab0e38203620249f0f100 -1f8670a594bb6f51563bd9bf29b0be9db17c3eda72bd1659dfd41852e3979832=6130ff60005260006002601e6001f500 -6a15f4010209e64618b949bedf2e4fd68305edffc11f62c9e2750d1fa3c9de0f=6a6130ff6000526002601ef36000526000600b60156001f55060006000600060006000736cd0e5133771823da00d4cb545ec8cdab0e38203620249f0f100 -e904075f6bb91684919a73b6f6c2faad062ac28e0d1b4b0324e37dfaed73f2bf=6b626001ff6000526003601df36000526000600c60146000f5506000600060006000735649527a8464a86cae579719d347065f6eb27279620249f0fa00 -320c0bdac224010fc389c11ded0214972cede15725f62d68bb368ebaa343fe00=6b626001ff6000526003601df36000526000600c60146001f5506000600060006000735649527a8464a86cae579719d347065f6eb27279620249f0fa00 -6adc11cbb07e63284761e20c84dd42c2f0357cf416a9765221b113cc8496b91b=6a6130ff6000526002601ef36000526000600b60156000f5506000600060006000736cd0e5133771823da00d4cb545ec8cdab0e38203620249f0fa00 -9444e91fe9e94eb25af4daa9780ce737e1a4ffdad450b59d459feb44b5cd1de9=6a6130ff6000526002601ef36000526000600b60156001f5506000600060006000736cd0e5133771823da00d4cb545ec8cdab0e38203620249f0fa00 -b9134334f82ce111680bb32468b9df3d41061303d1511e4b9361eb7d22dbbd74=30506000600e80602860003960006000f56002553d6000556020600060003e6000516001550000fe6211223360005260206000fd0000 -c79e0198cf5bd2391dfab79ab4a5f727191b360097e4480f46ba6b55343c6fd1=60006000536000600160006000f560005500 -a1c0af891959756f7603db930bde8c199d25c3b45e93892f65e2fc58a6e84d01=60566000536000600160006000f560005500 -170d0e39252912ff91a1ecaca213518f87e5ab208f0b1de87b643d79b6e5a7dc=60016000536000600160006000f560005500 -5fbdc0a1ec766446c7bb63bf261e8d9c551ba3bee3b01ad04ec855610a90c555=60f46000536000600160006000f560005500 -76a20ad723a19ff6ee0f1fb94b0e4266f5a2c7bf3fb869320dab8c233fb8d7b1=6a60016001556001546002556000526000600b60156000f560005500 -af92af26df14fab9cfeacf2d1ea273af589f14a70a6a9f85c81fb3b8a1a9634e=626001ff60005260006003601d6000f560005500 -1f224ef3dee7bce1e818896ba56cea12fa5929f5322ff3cc30935666a995a355=626001ff60005260006003601d6001f560005500 -343399ee1d228e1f9967c71d5018fcb3a10487d7158a3686918df63869426864=60006003601d6000f560005500 -4dea22089412be26f403665dec5b440f064752f4e3f1580981b6f743f6914f10=6160a960005260006002601e6001f560005500 -fd39994f2b05bfbff9216d2e0ff446e83c2504d25ac18ca1c69efbf13d5ce691=6000600060006000f500 -8709980edfa2db2bca11f56a4f8ccf4f40130495b192afc3d66338be29c79fe8=64600160015560005260006005601b6000f500 -edc3d79069c655807240f56f6d25b23bc70fb7f74b6c3c72ceb022842193cf96=6000600060006001f500 -97701eaa65e57bfd257e872adbadb1564174326e325d358f9074c94c3982d68d=6b620102036000526003601df36000526000600c60146000f500 -81857195aa42f0d424d0f68d3d53dbbbc556c4baf6ffb3c5f3434996a3080652=6b620102036000526003601df36000526000600c60146001f500 -a33f1f7f11cd1cf39ca6dd8efa5bf35dcccf71aa76f5b483936b4c9b1303ece5=6000600060006000600073fce41d047b4a1d4450382dcc29ec7e5fedc5f9a361c350f1506b620102036000526003601df36000526000600c60146000f500 -08526b9d35d551a58be04ac9d2112ea7b61296f9997ed1b813f90eda1d170f7f=6000600060006000600073cff64f4c5df8f436c4f2c1af4b2e3f9e3004c77961c350f1506b626010ff6000526003601df36000526000600c60146000f500 -a5ba2215589e9001f8e09e6d4b20d10984ccf41127a7c1541412d8a143cc9ed5=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c61c350f1506000600060006000f500 -b67531ccc44e5125b256f0a2ddbc2dd196a581ec2ecc6036111856343cb11b23=6000600060006000600073af3ecba2fe09a4f6c19f16a9d119e44e08c2da0161c350f15064600160015560005260006005601b6000f500 -751304facb1eaaf42eac0410f7c198c2bccec0ef5f539437540b863e2227c34c=6000600060006000600073ec2c6832d00680ece8ff9254f81fdab0a5a2ac5061c350f1506d6460016001556000526005601bf36000526000600e60126000f500 -8098eeb5bc9d57bdc6a129d382eceb3ae0cddbf1b097becd1525a3ef74dd8720=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c61c350f1506000600060006000f5506211223360005500 -3079d3cb0f0da4e5498df92c5d46dea0149cf57011aa0a6b734b2ca5c8829660=6000600060006000600073af3ecba2fe09a4f6c19f16a9d119e44e08c2da0161c350f15064600160015560005260006005601b6000f5506211223360005500 -3713ee134881ec75e4d2dddc2e794f0d413f667ea2f7318b2b356fe7487f7802=6000600060006000600073ec2c6832d00680ece8ff9254f81fdab0a5a2ac5061c350f1506d6460016001556000526005601bf36000526000600e60126000f5506211223360005500 -b241e18beb9a689473427ca122ae13c4923908e5f245ceae722019fd848d1b15=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c61c350f1506000600060006000f550621122336000526003601dfd00 -05711be14dd842613c5207685cb7989b9e037d5560062bf20b630ed3c0ac5e34=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c61c350f15064600160015560005260006005601b6000f550621122336000526003601dfd00 -e24df00f2cc0d6b3c1fad7bbe374fdca414384c13d4aa0a379ae6015ec40c656=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c61c350f1506d6460016001556000526005601bf36000526000600e60126000f550621122336000526003601dfd00 -f3802b7c46d0e643142b13742279ae9721de44f8617aafbd5b0a68f8ea8731d5=6000600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c620249f0f100 -5522f10e8623be56f3fcc3a05e5dbd29520a6bf3092eb495d60553cfa1973e9e=6000600060006000600173e2b35478fdd26477cc576dd906e6277761246a3c620249f0f100 -a1f611faeec2bab60b99b53874198369701ba7d12bf2b948d2711c73d6b4679a=600060006000600073e2b35478fdd26477cc576dd906e6277761246a3c620249f0fa00 -feb9ba92c6e4987a294d23df9744fa757212a3569df905c03675e5b2d6dae93e=73b94f5374fce5edbc8e2a8697c15331677e6ebf0b3f60005573b94f5374fce5edbc8e2a8697c15331677e6ebf0b3b60015500 -e1991ac4134897e9ab2d8767c5831f37c9e21878c52c0c2385429aa4849430f7=6000603380601360003960006000f5500000fe73b94f5374fce5edbc8e2a8697c15331677e6ebf0b3f60005573b94f5374fce5edbc8e2a8697c15331677e6ebf0b3b60015500 -9697d016645564aeb2639c2d88c07e6954b66c78b4e4319d1030e7591481b591=600980601160003960006001f0500000fe621122336000550000 -53a1824fc1a4451a418c68bbf4a08b9e1814e872d34c49af967d79e2454f988f=3050600d80602460003960006000f0503d6000556020600060003e6000516001550000fe6211223360005260206000fd00 -b4c5e7abf2c1e7d3ab977f12b44b93ae99ea6b4ce5c670a962d342aa6028203c=6000600155600160015500 -438fe345117cd7ad596753bcf57091f81c32dfca164e1b45269b97cf9c09e879=6000600b80601360003960006000f5500000fe6000600155600160015500 -3bf29bf3eb0c4135fa025457b168546cb4980523dd9f0aa748f7d95c092e034b=6000600b80601860003960006000f55060006000fd0000fe6000600155600160015500 -8fecce8e335fb1fb2a6807744153cbeee93c36edfeb191e66e4c005beda348aa=6000600b80603860003960006000f5506000600060006000600073dea000000000000000000000000000000000000062030d40f1500000fe6000600155600160015500 -f7ecb300fa680c5646609e246335b9590eae3984cc8e9d877a6d1a96dd78d06f=6000600b80603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe6000600055600160015500 -8e8cced5a66880190481484ebc888f016abf26edb6b63952fd56ad9902fc8abf=6000600b80603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe6000600055600160015500 -41e9c2b79ea10471c568869d4e417496b4d7da183b67a40d98ccfcb485724f49=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60006000556000600055600160015500 -d5ea3c39ab410861d60d2b43a169701ee20db5eddc5d2ca0f18455f44aaa2e5a=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60006000556000600055600160015500 -29a0de90a0b1555166a33a0119fb0608f211fca9e1f8a5ff8b4275ea3a1e9b41=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60006000556001600055600160015500 -049384d05388927ad43efec6f0e1094d6756dae21882f25ca3cee69993b00539=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60006000556001600055600160015500 -51c9574629bcf5d57a6d1ae22edbe947c373fae8443a36d28ac67924fd179223=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60016000556000600055600160015500 -8b1c576fd5dde376e5dd2c272ed032832da9e421b26b58ecc428d04b24ea8842=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60016000556000600055600160015500 -f0deaf54708e026c126bd71b87345c00a82f1db41a00cd1a155e79ed86f28826=6000601a80603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe6000600055600160005560006000556001600055600160015500 -7f94638cc54702bf94933a6d1ee2f1ffbacb385733403aaa3c6b1134bbdbfdb9=6000601a80603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe6000600055600160005560006000556001600055600160015500 -782cc82a9fcab1d050728fbf61ed4f67aa3795eba9ab5ec32b153d9b69df1c02=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60016000556001600055600160015500 -bbdc0c21f43d7cc053dbfa83471f6eb5f20a8e8bd472a3455b830ee3dad4cd74=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60016000556001600055600160015500 -0147f11f9e025d0345e7299b37b2dd707acec8ad89932fbf478ad10eec37cf07=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60026000556001600055600160015500 -5b8500988fe75e09a7750264018eb01eda3e06312d7eee426f53944ea14a9969=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60026000556001600055600160015500 -55f860845bb4e5a266cf4be224ebe6b2ac36b720657080be02aa64be357ca0d4=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560006000556000600055600160015500 -5e37109701f2b28987aa472047648319f4c383bb996bde2678b8dd90709fdfcf=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560006000556000600055600160015500 -717d575e4c7e9d1a93058587fbf452ba70f94612d632cc8c59606a54b63fc149=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560006000556001600055600160015500 -3e4bb760c8f9af445c0136087aed8cb2505c0f03190d676afc3dd8691f2639cb=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560006000556001600055600160015500 -ee080d677112344e86df581a9c0000bf1345d63e141dd3001a133cb4bca6c820=6000601a80603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe6001600055600060005560016000556000600055600160015500 -fb683cf50f9889a6f3bf08aaa86d3a56744cf65e705b0ca5429bbaf749d5581d=6000601a80603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe6001600055600060005560016000556000600055600160015500 -9bbfcdc8698cb4033516bf18944810b6ef0b246029edaa95e4204adc9b786ad2=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600260005560006000556001600055600160015500 -55eeb5d356b4d29875392900da428340d11a6924e38b75dbe8e90899433a01d2=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600260005560006000556001600055600160015500 -2570c15ef683a5de7fc0f6be4b25d3b1a0e06af713f7cfeea6fff59f7853ebec=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560016000556000600055600160015500 -5107cef9dddfac3d9e3e45b5c9b365c4415c28a8e0472569ef7128e58ba1f680=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560016000556000600055600160015500 -86c686872a48a822b3175ebc1d99ba3510440ecd2ae25e60234ded212856d7cb=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560016000556001600055600160015500 -b3a8f1d1466d1f3fd7d30047dc29fba75a38056e205e500d9e9f6e193d52e656=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560016000556001600055600160015500 -447a1225165db03d156c0de00234f4e929ff00982d0fd7ce6cf9698950e645e9=6000601080603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe60016000556002600055600160015500 -0999679fee9c935b7bc602007c765c601ece025c88922e0ab503b4979cf741b5=6000601080603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe60016000556002600055600160015500 -c66e1669b097202bdf2367fa4a09c5ccede3a735449427cfda2210bd06c854d5=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560026000556000600055600160015500 -12ea25982a4c21ade8cc1543d8d3fcdfe9b641c24446658bdbdcbbad8820f74e=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560026000556000600055600160015500 -ae838bf60cbee93b47a9cdac70c9c2a62962c9fe975a68d0c07fe244fc8c9558=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560026000556001600055600160015500 -38cb8e8bad41f6c090d9e5746cf6173181b0aa11df92f99dc0aa0db729c8583f=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560026000556001600055600160015500 -86604fd79d1febe3ea6b3a5e5e3c5afe4d72e3fb144d5865033b6d3f4cb9a57a=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600260005560016000556001600055600160015500 -ffc7be0afa74c4bcd22e2fb76fac391eac9534dc12856b760f1911250ecf20be=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600260005560016000556001600055600160015500 -3af869d3aa41bf3132ec73926890abb26811807c9e27853fd42c258fceb121c4=6000601580603860003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f1500000fe600160005560026000556003600055600160015500 -80bd7d9f5068f3812d8a63a4ed6e9a3851fa3b7ef361b651ddb8aef1b3d580f3=6000601580603d60003960006000f5506000600060006000600073dea0000000000000000000000000000000000000620927c0f15060206000fd0000fe600160005560026000556003600055600160015500 -f757fae5f4eb63182517dbb919fa741b10dadf37687c7f52d42c8ac981bbbe0f=6000600060006000600073bea0000000000000000000000000000000000000620186a0f100 -a9ab7f2212c8e46134059b4c7b825ba002f67fc95b931863bd93dcf8d947d722=6000602580601360003960006000f5500000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f100 -4b6b2913c5edfc9cf7aa4dfd41047495409ad32ce3aeb84c5375f8ea6055bfbc=6000602580601860003960006000f55060006000fd0000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f100 -d075320df7bd25b27cc3687b005c8779e3f5ad8cec0acbb6ebd91970c5fa2fc0=6000602580603860003960006000f5506000600060006000600073dea000000000000000000000000000000000000062030d40f1500000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f100 -de5ccc55fa69e6da7a061c64dbaa7810dcb8861feea2eae5e3c77a4f40ad5ec4=6000600060006000600073bea0000000000000000000000000000000000000620186a0f200 -02d0e9785e8763983715149b65b21a031d3ebde207581f12d7d09b0d10946394=6000602580601360003960006000f5500000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f200 -19225772c6a134782d03ad56908709d172fb07c5ee35e71a6b70f2e533ab558b=6000602580601860003960006000f55060006000fd0000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f200 -d3ac721d201b205ef46f4e6dd82f9231ac71d39b0a19bbe18c5dde5ddc9de7cd=6000602580603860003960006000f5506000600060006000600073dea000000000000000000000000000000000000062030d40f1500000fe6000600060006000600073bea0000000000000000000000000000000000000620186a0f200 -f92e3935274932032c772dbbcbc224203869b4b2efc171e5ec5a23579d8cd846=600060006000600073bea0000000000000000000000000000000000000620186a0f400 -905a47cdd17e3fbcb986f8c5f1f764645743641462c178a5a116c12c60916974=6000602380601360003960006000f5500000fe600060006000600073bea0000000000000000000000000000000000000620186a0f400 -10472629d0f6168352db4aa653c15990c97621e6522c403bab029f577d06d9b8=6000602380601860003960006000f55060006000fd0000fe600060006000600073bea0000000000000000000000000000000000000620186a0f400 -8d917969ad8373792c4cf0d64acc12a5ab59494433a2fd384830ce73f34f1411=6000602380603860003960006000f5506000600060006000600073dea000000000000000000000000000000000000062030d40f1500000fe600060006000600073bea0000000000000000000000000000000000000620186a0f400 -086087e15b5c513c69f51269d3206f488eeb45eade598ed5790cc6a8892a7db3=600060006000600073bea0000000000000000000000000000000000000620186a0fa00 -63462454d8c043fa2d283b69e632789b28c1a91a3f74a9be9ad332a6fb24f395=6000602380601360003960006000f5500000fe600060006000600073bea0000000000000000000000000000000000000620186a0fa00 -6039a8923c6f7c28763f3221f81b54030bcfc70637d4205c581d929c60f3ed35=6000602380601860003960006000f55060006000fd0000fe600060006000600073bea0000000000000000000000000000000000000620186a0fa00 -472679aaf2fd729d45bdf351f55e1f1efb1698d35a93444ea2725f760d1cb5e8=6000602380603860003960006000f5506000600060006000600073dea000000000000000000000000000000000000062030d40f1500000fe600060006000600073bea0000000000000000000000000000000000000620186a0fa00 -6e7b859102a29fa992c7eda66444f62a8511cc1ab19d4ea736765c792049cdcc=6000600060006000600073b000000000000000000000000000000000000000610901f115604b576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 -b2e74ed55d92f82a05f2113bf763854ae51caf3afcb618d6469feb1223db0a46=6000600060006000600073b000000000000000000000000000000000000000610902f115604b576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 -6c90cf457538e29694799179f698cc875b1ea95c297387e478de97c775674b1d=6000600060006000600073b000000000000000000000000000000000000000610903f115604b576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 -e798273f90ee37816ec2050556e4ccb681c0a17dbe4ff09abf7ba18e33f8459b=60016001556000600060006000600073b000000000000000000000000000000000000000610901f2156050576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 -3db68f13d49b2350284bd754957b34f1105923ef81af8476014ccdb37b13b09d=60016001556000600060006000600073b000000000000000000000000000000000000000610902f2156050576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 -885b5bce0ccc44b9ef0c3b25fdc8d0c36fd298c73bb3c630c76e3558d7a8bfb2=60016001556000600060006000600073b000000000000000000000000000000000000000610903f2156050576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 -148d0d09c7fe4dda5404ea7f5c71746264665aa81789b1b130eb27b35140e53a=6001600155600060006000600073b000000000000000000000000000000000000000610901f415604e576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 -875cbaee3f9ca78b36415c70403eafcd88c66543127982f5f89b3b06123963f9=6001600155600060006000600073b000000000000000000000000000000000000000610902f415604e576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 -2deb9469ef0902c49112f3d39d76c543221f25edf34221b99bf612720ce063ef=6001600155600060006000600073b000000000000000000000000000000000000000610903f415604e576000600060006000600073c000000000000000000000000000000000000000617530f1505b00 -e3419aa3349648119d7ac284de0dba8e063dd870c78693f5d1f977e8c7f10531=3050600d80601360003960006000f050fe00fe6211223360005260206000fd00 -5598916aa5224e161a88881cdcdf6d07e2660a4863e6a00ea4ab8bc257f3dcb0=7f18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c600052601c6020527f73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f6040527feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c454960605260206103e860806000600162061a80fa60005560a060020a6103e851066001556001543214600255600060005260006020526000604052600060605260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060025afa6003556000516004556103e851600555600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060035afa6006556000516007556103e851600855600060005260006103e8527c0ccccccccccccccccccccccccccccccccccccccccccccccccccc00000060005260206103e86020600060045afa6009556103e851601055600060005260006103e8526001600052602060205260206040527f03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6060527f2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc6080527f2f0000000000000000000000000000000000000000000000000000000000000060a05260206103e860a1600060055afa6011556103e85160125560006000526000602052600060405260006060526000608052600060a05260006103e8527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba6020527f1de49a4b0233273bba8146af82042d004f2085ec982397db0d97da17204cc2866040527f0217327ffc463919bef80cc166d09c6172639d8589799928761bcd9f22c903d460605260406103e86080600060065afa6013556103e85160145561040851601555600060005260006020526000604052600060605260006103e8526000610408527f0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd26000527f16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba602052600360405260406103e86060600060075afa6016556103e8516017556104085160185560006000526000602052600060405260006103e8526000610408527f1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f596000527f3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef416020527f209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf76040527f04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416786060527f2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d6080527f120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de87755060a0527f111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c60c0527f2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf41160e0527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2610100527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed610120527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b610140527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa6101605260206103e8610180600060085afa6019556103e85160205500 -0a614964c672e15a4d50346ccbbd43debd239d03dec56e7daccd06a2d430e928=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110010000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -bd8e9570497da58a1e7a4fceec87eae435f91aaa48ecea0936bad917aba5d805=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110020000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -b1a5e754bbbd98759d83a64057317f6e3bf4755539a0de0d2d01bb68c456a1ba=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110030000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -b4d2be0cfe7c0fd138fc1a307c2d7a20d3a6f7cf908b3257c1e3077a9e969dc5=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110040000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -8dbbdbafb844667151cad451f4da1f4ac1e3e6b20f6ae17b890d2d68ec73e389=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110050000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -cd3b6dabee431709fc2561e4888c5169939a38419d4a3205044e82be5a053ef6=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110060000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -70b83ebf52c9d6bde3d6afa24d3d2b480bad4c62a10037f3950f09cf70c19edd=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110070000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 -feb32c5cc73e034f2e04193cd35fb6157ec84745bdf2b01d3708437922053865=7ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed600055600060006000600073ca110080000000000000000000000000000000005afa6001557ffeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed60025500 diff --git a/testool/debug.sh b/testool/debug.sh deleted file mode 100755 index 55dbf1c4fe..0000000000 --- a/testool/debug.sh +++ /dev/null @@ -1 +0,0 @@ -RUST_BACKTRACE=1 cargo run -- --path "tests/src/GeneralStateTestsFiller/**/*" --skip-state-circuit --test $* diff --git a/testool/docker/solc/Dockerfile b/testool/docker/solc/Dockerfile index 5dec96db52..16b58ac0ca 100644 --- a/testool/docker/solc/Dockerfile +++ b/testool/docker/solc/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine AS build +FROM alpine:3.15.6 AS build WORKDIR /solidity diff --git a/testool/loop.sh b/testool/loop.sh deleted file mode 100755 index 132af8b3e2..0000000000 --- a/testool/loop.sh +++ /dev/null @@ -1,4 +0,0 @@ -while : -do - cargo run --release -- --path "tests/src/GeneralStateTestsFiller/**/*" --skip-state-circuit -done diff --git a/testool/pre_commit.sh b/testool/pre_commit.sh deleted file mode 100755 index e14be593e1..0000000000 --- a/testool/pre_commit.sh +++ /dev/null @@ -1,5 +0,0 @@ -cargo fmt -cargo clippy -- -Dwarnings -W clippy::pedantic -cargo update -cargo test -cargo outdated --root-deps-only diff --git a/testool/raw.sh b/testool/raw.sh deleted file mode 100755 index 280500d43d..0000000000 --- a/testool/raw.sh +++ /dev/null @@ -1,2 +0,0 @@ -cargo run --release -- --raw $* - diff --git a/testool/src/abi.rs b/testool/src/abi.rs index 59bc06c78b..604463702a 100644 --- a/testool/src/abi.rs +++ b/testool/src/abi.rs @@ -76,8 +76,7 @@ mod test { #[test] fn test_abi_encoding() -> Result<()> { - // [TODO] does not match with - // https://github.com/ethereum/tests/blob/0e8d25bb613cab7f9e99430f970e1e6cbffdbf1a/GeneralStateTests/VMTests/vmArithmeticTest/add.json#L244 + // matches with https://raw.githubusercontent.com/ethereum-lists/4bytes/master/with_parameter_names/b3de648b assert_eq!( hex::encode(encode_funccall("f(uint) 4")?), "b3de648b0000000000000000000000000000000000000000000000000000000000000004" diff --git a/testool/src/compiler.rs b/testool/src/compiler.rs index 04e7a18d31..1a45162a63 100644 --- a/testool/src/compiler.rs +++ b/testool/src/compiler.rs @@ -1,15 +1,16 @@ #![allow(clippy::map_entry)] use anyhow::{bail, Context, Result}; -use eth_types::{bytecode, Bytecode}; -use eth_types::{Bytes, H256}; +use eth_types::{bytecode, Bytecode, Bytes, H256}; use keccak256::plain::Keccak; -use std::collections::HashMap; -use std::io::Read; -use std::io::Write; -use std::path::PathBuf; -use std::process::{Command, Stdio}; -use std::str::FromStr; +use serde::{Deserialize, Serialize}; +use std::{ + collections::HashMap, + io::{Read, Write}, + path::PathBuf, + process::{Command, Stdio}, + str::FromStr, +}; struct Cache { entries: HashMap, @@ -65,6 +66,139 @@ impl Cache { } } +#[derive(Debug, Serialize, Deserialize)] +struct CompilerInput { + language: Language, + settings: CompilerSettings, + sources: HashMap, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "PascalCase")] +enum Language { + Solidity, + Yul, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct CompilerSettings { + optimizer: Optimizer, + output_selection: HashMap>>, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Optimizer { + enabled: bool, + details: HashMap, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Source { + content: String, +} + +impl CompilerInput { + pub fn new_default(language: Language, src: &str) -> Self { + let mut sources = HashMap::new(); + sources.insert( + "stdin".to_string(), + Source { + content: src.to_string(), + }, + ); + CompilerInput { + language, + settings: Default::default(), + sources, + } + } +} + +impl Default for CompilerSettings { + fn default() -> Self { + let mut output_selection = HashMap::new(); + let mut selection = HashMap::new(); + selection.insert("*".to_string(), vec!["evm.bytecode".to_string()]); + output_selection.insert("*".to_string(), selection); + CompilerSettings { + optimizer: Default::default(), + output_selection, + } + } +} + +impl Default for Optimizer { + fn default() -> Self { + let mut details = HashMap::new(); + details.insert("peephole".to_string(), false); + details.insert("inliner".to_string(), false); + details.insert("jumpdestRemover".to_string(), false); + Optimizer { + enabled: false, + details, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct CompilationResult { + contracts: HashMap>, + errors: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Contract { + evm: Evm, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct Evm { + bytecode: BytecodeResult, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct BytecodeResult { + object: String, + opcodes: String, + source_map: String, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct CompilationError { + component: String, + error_code: String, + formatted_message: String, + message: String, + severity: Severity, + #[serde(rename = "type")] + error_type: String, + source_location: Option, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +enum Severity { + Error, + Warning, + Info, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct SourceLocation { + end: i32, + file: String, + start: i32, +} + #[derive(Default)] pub struct Compiler { cache: Option, @@ -142,64 +276,42 @@ impl Compiler { /// compiles YUL code pub fn yul(&mut self, src: &str) -> Result { - if let Some(bytecode) = self.cache.as_mut().and_then(|c| c.get(src)) { - return Ok(bytecode.clone()); - } - if !self.compile { - bail!("No way to compile Yul for '{}'", src) - } - - let stdout = Self::exec( - &["run", "-i", "--rm", "solc", "--strict-assembly", "-"], - src, - )?; - let placeholder = "Binary representation:\n"; - let from_pos = stdout.find(placeholder); - let len = from_pos.and_then(|pos| stdout[pos + placeholder.len()..].find('\n')); - let bytecode = if let (Some(from_pos), Some(len)) = (from_pos, len) { - let hex = &stdout[from_pos + placeholder.len()..from_pos + placeholder.len() + len]; - Bytes::from(hex::decode(&hex)?) - } else { - bail!("Unable to compile: {}", src); - }; - if let Some(cache) = &mut self.cache { - cache.insert(src, bytecode.clone())?; - } - - Ok(bytecode) + self.solc(Language::Yul, src) } + /// compiles Solidity code pub fn solidity(&mut self, src: &str) -> Result { + self.solc(Language::Solidity, src) + } + + fn solc(&mut self, language: Language, src: &str) -> Result { if let Some(bytecode) = self.cache.as_mut().and_then(|c| c.get(src)) { return Ok(bytecode.clone()); } if !self.compile { - bail!("No way to compile Solidity for '{}'", src) + bail!("No way to compile {:?} for '{}'", language, src) } + let compiler_input = CompilerInput::new_default(language, src); let stdout = Self::exec( - &[ - "run", - "-i", - "--rm", - "solc", - "--bin", - "--optimize", - "--metadata-hash", - "none", - "-", - ], - src, + &["run", "-i", "--rm", "solc", "--standard-json", "-"], + serde_json::to_string(&compiler_input).unwrap().as_str(), )?; - let placeholder = "Binary:\n"; - let from_pos = stdout.find(placeholder); - let len = from_pos.and_then(|pos| stdout[pos + placeholder.len()..].find('\n')); - let bytecode = if let (Some(from_pos), Some(len)) = (from_pos, len) { - let hex = &stdout[from_pos + placeholder.len()..from_pos + placeholder.len() + len]; - Bytes::from(hex::decode(&hex)?) - } else { - bail!("Unable to compile: {}", src); - }; + let mut compilation_result: CompilationResult = serde_json::from_str(&stdout)?; + let bytecode = compilation_result + .contracts + .remove("stdin") + .expect("should have stdin") + .into_iter() + .next() + .expect("should have one contract") + .1 + .evm + .bytecode + .object; + + let bytecode = Bytes::from(hex::decode(bytecode)?); + if let Some(cache) = &mut self.cache { cache.insert(src, bytecode.clone())?; } diff --git a/testool/src/config.rs b/testool/src/config.rs index 8168352697..6e89598cb3 100644 --- a/testool/src/config.rs +++ b/testool/src/config.rs @@ -1,35 +1,117 @@ -use anyhow::{Context, Result}; -use eth_types::evm_types::OpcodeId; +use anyhow::{anyhow, bail, ensure, Context, Result}; use serde::Deserialize; +const CONFIG_FILE: &str = "Config.toml"; + #[derive(Debug, Clone, Deserialize)] pub struct Config { + pub suite: Vec, + pub set: Vec, + pub skip_paths: Vec, + pub skip_tests: Vec, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct TestSuite { + pub id: String, + pub path: String, pub max_gas: u64, pub max_steps: u64, - /// see [Implemented opcodes status](https://github.com/appliedzkp/zkevm-circuits/issues/477) - pub unimplemented_opcodes: Vec, - pub ignore_test: Vec, - pub skip_path: Vec, - pub skip_test: Vec, + ignore_tests: Option>, + allow_tests: Option>, +} + +impl Default for TestSuite { + fn default() -> Self { + Self { + id: "default".to_string(), + path: String::default(), + max_gas: u64::MAX, + max_steps: u64::MAX, + ignore_tests: Some(Vec::new()), + allow_tests: None, + } + } +} + +impl TestSuite { + pub fn allowed(&self, test_id: &str) -> bool { + if let Some(ignore_tests) = &self.ignore_tests { + ignore_tests + .binary_search_by(|id| id.as_str().cmp(test_id)) + .is_err() + } else if let Some(allow_tests) = &self.allow_tests { + allow_tests + .binary_search_by(|id| id.as_str().cmp(test_id)) + .is_ok() + } else { + unreachable!() + } + } } impl Config { pub fn load() -> Result { - let content = std::fs::read_to_string("./Config.toml")?; - let toml: Result = toml::from_str(&content); - toml.context("parsing toml") + let content = std::fs::read_to_string(CONFIG_FILE) + .context(format!("Unable to open {}", CONFIG_FILE))?; + let mut config: Config = toml::from_str(&content).context("parsing toml")?; + + // Append all tests defined in sets into the tests + config.suite = config + .suite + .clone() + .into_iter() + .map(|mut suite| { + let (allow, defined) = match (&suite.allow_tests, &suite.ignore_tests) { + (Some(allow), None) => (true, allow), + (None, Some(ignore)) => (false, ignore), + _ => bail!("ignore_tests or allow_tests should be specified"), + }; + let mut all = Vec::new(); + for test_name in defined { + if let Some(setname) = test_name.strip_prefix('&') { + let set: Vec<_> = config.set.iter().filter(|ts| ts.id == setname).collect(); + ensure!(!set.is_empty(), "no tests sets found for id '{}'", setname); + set.iter().for_each(|ts| all.append(&mut ts.tests.clone())); + } else { + all.push(test_name.clone()); + } + } + all.sort(); + if allow { + suite.allow_tests = Some(all); + } else { + suite.ignore_tests = Some(all); + } + Ok(suite) + }) + .collect::>()?; + Ok(config) + } + pub fn suite(&self, name: &str) -> Result<&TestSuite> { + self.suite + .iter() + .find(|s| s.id == name) + .ok_or_else(|| anyhow!("Suite not found")) } } #[derive(Debug, Clone, Deserialize)] -pub struct SkipPath { +pub struct TestsSet { + pub id: String, + pub desc: Option, + pub tests: Vec, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct SkipPaths { pub desc: Option, pub paths: Vec, } #[derive(Debug, Clone, Deserialize)] -pub struct SkipTest { +pub struct SkipTests { pub desc: Option, - pub ids: Vec, + pub tests: Vec, } diff --git a/testool/src/main.rs b/testool/src/main.rs index 715416d665..caf7df3f49 100644 --- a/testool/src/main.rs +++ b/testool/src/main.rs @@ -5,15 +5,18 @@ mod config; mod statetest; mod utils; +use crate::{config::TestSuite, statetest::ResultLevel}; use anyhow::{bail, Result}; use clap::Parser; use compiler::Compiler; use config::Config; -use statetest::{load_statetests_suite, run_statetests_suite, Results, StateTest, StateTestConfig}; -use std::path::PathBuf; -use std::process::Command; -use std::time::SystemTime; -use zkevm_circuits::test_util::BytecodeTestConfig; +use log::info; +use statetest::{ + geth_trace, load_statetests_suite, run_statetests_suite, run_test, CircuitsConfig, Results, + StateTest, +}; +use std::{collections::HashSet, path::PathBuf, time::SystemTime}; +use strum::EnumString; const REPORT_FOLDER: &str = "report"; const CODEHASH_FILE: &str = "./codehash.txt"; @@ -21,201 +24,213 @@ const CODEHASH_FILE: &str = "./codehash.txt"; #[macro_use] extern crate prettytable; +#[allow(non_camel_case_types)] +#[derive(PartialEq, Parser, EnumString, Debug)] +enum Circuits { + basic, + sc, +} + /// EVM test vectors utility #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args { - /// (Ethereum tests) path - #[clap(long, default_value = "tests/src/GeneralStateTestsFiller/**")] - ethtest: String, + /// Suite (by default is "default") + #[clap(long, default_value = "default")] + suite: String, - /// (Ethereum tests) execute one test and dump the results + /// Execute only one test and dump the results #[clap(long)] - ethtest_id: Option, + inspect: Option, - /// (Ethereum tests) Cache execution results + /// Do not execute any test, just list collected tests #[clap(long)] - ethtest_cache: bool, + ls: bool, - /// (Ethereum tests) Run all ignored tests (skipped ones are not executed) + /// Cache execution results #[clap(long)] - ethtest_all: bool, + cache: Option, - /// (Ethereum tests) CI mode: generates log and and html file with info. - /// Doesn't skip any test. - #[clap(long)] - ci: bool, + /// whitelist level from cache result + #[clap(short, long, value_parser, value_delimiter = ',')] + levels: Vec, - /// Do not run any circuits + /// Generates log and and html file with info. #[clap(long)] - skip_circuit: bool, + report: bool, - /// Do not run state circuit + /// Run statetest in oneliner spec #[clap(long)] - skip_state_circuit: bool, + oneliner: Option, - /// Raw execute bytecode, can be hex `6001` or asm `PUSH1(60); PUSH1(60)` + /// Circuits to execute, can be basic (evm only) or sc (supercircuit) #[clap(long)] - raw: Option, + circuits: Option, /// Verbose #[clap(short, long)] v: bool, } -const RESULT_CACHE: &str = "result.cache"; - -fn run_single_test(test: StateTest, config: StateTestConfig) -> Result<()> { +fn run_single_test(test: StateTest, circuits_config: CircuitsConfig) -> Result<()> { println!("{}", &test); - - let trace = test.clone().geth_trace()?; + let trace = geth_trace(test.clone())?; crate::utils::print_trace(trace)?; - println!("result={:?}", test.run(config)); - - Ok(()) -} - -fn run_bytecode(code: &str, bytecode_test_config: BytecodeTestConfig) -> Result<()> { - use eth_types::bytecode; - use mock::TestContext; - use std::str::FromStr; - use zkevm_circuits::test_util::run_test_circuits; - - let bytecode = if let Ok(bytes) = hex::decode(code) { - match bytecode::Bytecode::try_from(bytes.clone()) { - Ok(bytecode) => { - for op in bytecode.iter() { - println!("{}", op.to_string()); - } - bytecode - } - Err(err) => { - println!("Failed to parse bytecode {:?}", err); - bytecode::Bytecode::from_raw_unchecked(bytes) - } - } - } else { - let mut bytecode = bytecode::Bytecode::default(); - for op in code.split(';') { - let op = bytecode::OpcodeWithData::from_str(op.trim()).unwrap(); - bytecode.append_op(op); - } - println!("{}\n", hex::encode(bytecode.code())); - bytecode - }; - - let result = run_test_circuits( - TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode)?, - Some(bytecode_test_config), + println!( + "result={:?}", + run_test(test, TestSuite::default(), circuits_config) ); - - println!("Execution result is : {:?}", result); - Ok(()) } -fn main() -> Result<()> { +fn go() -> Result<()> { // RAYON_NUM_THREADS=1 RUST_BACKTRACE=1 cargo run -- --path // "tests/src/GeneralStateTestsFiller/**/" --skip-state-circuit - let mut config = Config::load()?; let args = Args::parse(); - let bytecode_test_config = BytecodeTestConfig { - enable_state_circuit_test: !args.skip_state_circuit, - ..Default::default() - }; - - let statetest_config = StateTestConfig { - run_circuit: !args.skip_circuit, - bytecode_test_config: bytecode_test_config.clone(), - global: config.clone(), - }; + let mut circuits_config = CircuitsConfig::default(); + if args.circuits == Some(Circuits::sc) { + circuits_config.super_circuit = true; + } - if let Some(raw) = &args.raw { - run_bytecode(raw, bytecode_test_config)?; + if let Some(oneliner) = &args.oneliner { + let test = StateTest::parse_oneline_spec(oneliner)?; + run_single_test(test, circuits_config)?; return Ok(()); } + let config = Config::load()?; + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); + log::info!("Using suite '{}'", args.suite); log::info!("Parsing and compliling tests..."); let compiler = Compiler::new(true, Some(PathBuf::from(CODEHASH_FILE)))?; - - if let Some(test_id) = args.ethtest_id { - // test only one - config.skip_test.clear(); - let state_tests = load_statetests_suite(&args.ethtest, config, compiler)?; - let mut state_tests: Vec<_> = state_tests - .into_iter() - .filter(|t| t.id == test_id) - .collect(); - if state_tests.is_empty() { + let suite = config.suite(&args.suite)?.clone(); + let state_tests = load_statetests_suite(&suite.path, config, compiler)?; + log::info!("{} tests collected in {}", state_tests.len(), suite.path); + + if args.ls { + let mut list: Vec<_> = state_tests.into_iter().map(|t| t.id).collect(); + list.sort(); + for test in list { + info!("{}", test); + } + return Ok(()); + } + if let Some(test_id) = args.inspect { + // Test only one and return + let mut state_tests_filtered: Vec<_> = + state_tests.iter().filter(|t| t.id == test_id).collect(); + if state_tests_filtered.is_empty() { + info!( + "Test '{}' not found but found some that partially matches:", + test_id + ); + for test in state_tests.iter().filter(|t| t.id.contains(&test_id)) { + info!("{}", test.id); + } bail!("test '{}' not found", test_id); } - run_single_test(state_tests.remove(0), statetest_config)?; - } else if args.ci { - // ci mode - config.skip_test.clear(); - let path = "tests/src/GeneralStateTestsFiller/**/*"; - - let state_tests = load_statetests_suite(path, config, compiler)?; - let output = Command::new("git") - .args(&["rev-parse", "HEAD"]) - .output() - .unwrap(); - let git_hash = String::from_utf8(output.stdout).unwrap(); - let git_hash = &git_hash[..7].to_string(); + run_single_test(state_tests_filtered.remove(0).clone(), circuits_config)?; + return Ok(()); + }; + + if args.report { + let git_hash = utils::current_git_commit()?; + let git_submodule_tests_hash = utils::current_submodule_git_commit()?; let timestamp = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .unwrap() .as_secs(); std::fs::create_dir_all(REPORT_FOLDER)?; - let csv_filename = format!("{}/{}.{}.csv", REPORT_FOLDER, timestamp, git_hash); - let html_filename = format!("{}/{}.{}.html", REPORT_FOLDER, timestamp, git_hash); + let csv_filename = format!( + "{}/{}.{}.{}.csv", + REPORT_FOLDER, args.suite, timestamp, git_hash + ); + let html_filename = format!( + "{}/{}.{}.{}.html", + REPORT_FOLDER, args.suite, timestamp, git_hash + ); + + // when running a report, the tests result of the containing cache file + // are used, but by default removing all Ignored tests + // Another way is to skip the test which level not in whitelist_levels + let mut previous_results = if let Some(cache_filename) = args.cache { + let whitelist_levels = HashSet::::from_iter(args.levels); + + let mut previous_results = Results::from_file(PathBuf::from(cache_filename))?; + if !whitelist_levels.is_empty() { + // if whitelist is provided, test not in whitelist will be skip + previous_results + .tests + .retain(|_, test| !whitelist_levels.contains(&test.level)); + } else { + // by default only skip ignore + previous_results + .tests + .retain(|_, test| test.level != ResultLevel::Ignored); + } - let mut results = Results::with_cache(PathBuf::from(csv_filename))?; - run_statetests_suite(state_tests, statetest_config, &mut results)?; + previous_results + } else { + Results::default() + }; + previous_results.set_cache(PathBuf::from(csv_filename)); + run_statetests_suite(state_tests, &circuits_config, &suite, &mut previous_results)?; // filter non-csv files and files from the same commit let mut files: Vec<_> = std::fs::read_dir(REPORT_FOLDER) .unwrap() .filter_map(|f| { let filename = f.unwrap().file_name().to_str().unwrap().to_string(); - (filename.ends_with(".csv") && !filename.contains(&format!(".{}.", git_hash))) - .then_some(filename) + (filename.starts_with(&format!("{}.", args.suite)) + && filename.ends_with(".csv") + && !filename.contains(&format!(".{}.", git_hash))) + .then_some(filename) }) .collect(); + files.sort_by(|f, s| s.cmp(f)); let previous = if !files.is_empty() { let file = files.remove(0); - println!("Comparing with previous results in {}", file); let path = format!("{}/{}", REPORT_FOLDER, file); + info!("Comparing with previous results in {}", path); Some((file, Results::from_file(PathBuf::from(path))?)) } else { None }; + let report = previous_results.report(previous); + std::fs::write(&html_filename, report.gen_html(git_submodule_tests_hash)?)?; - std::fs::write(&html_filename, results.report(previous).gen_html()?)?; - - println!("{}", html_filename); + report.print_tty()?; + info!("{}", html_filename); } else { - // manual - if args.ethtest_all { - config.skip_test.clear(); - } - let state_tests = load_statetests_suite(&args.ethtest, config, compiler)?; - let mut results = if args.ethtest_cache { - Results::with_cache(PathBuf::from(RESULT_CACHE))? + let mut results = if let Some(cache_filename) = args.cache { + Results::with_cache(PathBuf::from(cache_filename))? } else { Results::default() }; + log::info!("Executing..."); - run_statetests_suite(state_tests, statetest_config, &mut results)?; + run_statetests_suite(state_tests, &circuits_config, &suite, &mut results)?; + let success = results.success(); + log::info!("Generating report..."); results.report(None).print_tty()?; + + if !success { + std::process::exit(1); + } } Ok(()) } + +fn main() { + if let Err(err) = go() { + eprintln!("Error found {}", err); + } +} diff --git a/testool/src/statetest/executor.rs b/testool/src/statetest/executor.rs index 84a05e341b..c2c365d8f1 100644 --- a/testool/src/statetest/executor.rs +++ b/testool/src/statetest/executor.rs @@ -1,18 +1,20 @@ -use crate::config::Config; -use anyhow::Context; -use bus_mapping::circuit_input_builder::CircuitInputBuilder; -use bus_mapping::mock::BlockData; -use eth_types::{geth_types, geth_types::Account, Address, Bytes, GethExecTrace, H256, U256, U64}; -use ethers_core::types::TransactionRequest; -use ethers_signers::LocalWallet; +use super::{AccountMatch, StateTest, StateTestResult}; +use crate::config::TestSuite; +use bus_mapping::{ + circuit_input_builder::{CircuitInputBuilder, CircuitsParams}, + mock::BlockData, +}; +use eth_types::{geth_types, Address, Bytes, GethExecTrace, U256, U64}; +use ethers_core::{ + k256::ecdsa::SigningKey, + types::{transaction::eip2718::TypedTransaction, TransactionRequest}, +}; +use ethers_signers::{LocalWallet, Signer}; use external_tracer::TraceConfig; +use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use std::{collections::HashMap, str::FromStr}; use thiserror::Error; -use zkevm_circuits::test_util::BytecodeTestConfig; - -const EVMERR_OOG: &str = "out of gas"; -const EVMERR_STACKUNDERFLOW: &str = "stack underflow"; -const EVMERR_GAS_UINT64OVERFLOW: &str = "gas uint64 overflow"; +use zkevm_circuits::{super_circuit::SuperCircuit, test_util::CircuitTestBuilder, witness::Block}; #[derive(PartialEq, Eq, Error, Debug)] pub enum StateTestError { @@ -21,7 +23,7 @@ pub enum StateTestError { #[error("BalanceMismatch(expected:{expected:?}, found:{found:?})")] BalanceMismatch { expected: U256, found: U256 }, #[error("NonceMismatch(expected:{expected:?}, found:{found:?})")] - NonceMismatch { expected: U256, found: U256 }, + NonceMismatch { expected: u64, found: u64 }, #[error("CodeMismatch(expected: {expected:?}, found:{found:?})")] CodeMismatch { expected: Bytes, found: Bytes }, #[error("StorgeMismatch(slot:{slot:?} expected:{expected:?}, found: {found:?})")] @@ -30,461 +32,266 @@ pub enum StateTestError { expected: U256, found: U256, }, - #[error("SkipTesstMaxGasLimit({0})")] + #[error("SkipTestMaxGasLimit({0})")] SkipTestMaxGasLimit(u64), #[error("SkipTestMaxSteps({0})")] SkipTestMaxSteps(usize), - #[error("SkipUnimplemented({0})")] - SkipUnimplemented(String), #[error("Exception(expected:{expected:?}, found:{found:?})")] - Exception { expected: bool, found: bool }, + Exception { expected: bool, found: String }, } impl StateTestError { pub fn is_skip(&self) -> bool { matches!( self, - StateTestError::SkipUnimplemented(_) - | StateTestError::SkipTestMaxSteps(_) - | StateTestError::SkipTestMaxGasLimit(_) + StateTestError::SkipTestMaxSteps(_) | StateTestError::SkipTestMaxGasLimit(_) ) } } -#[derive(Debug, Clone)] -pub struct StateTestConfig { - pub run_circuit: bool, - pub bytecode_test_config: BytecodeTestConfig, - pub global: Config, +#[derive(Default, Debug, Clone)] +pub struct CircuitsConfig { + pub super_circuit: bool, } -impl Default for StateTestConfig { - fn default() -> Self { - Self { - run_circuit: true, - bytecode_test_config: BytecodeTestConfig::default(), - global: Config { - max_gas: 1000000, - max_steps: 2048, - unimplemented_opcodes: Vec::new(), - skip_path: Vec::new(), - skip_test: Vec::new(), - ignore_test: Vec::new(), - }, +fn check_post( + builder: &CircuitInputBuilder, + post: &HashMap, +) -> Result<(), StateTestError> { + // check if the generated account data is the expected one + for (address, expected) in post { + let (_, actual) = builder.sdb.get_account(address); + + if expected.balance.map(|v| v == actual.balance) == Some(false) { + return Err(StateTestError::BalanceMismatch { + expected: expected.balance.unwrap(), + found: actual.balance, + }); } - } -} - -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct Env { - pub current_coinbase: Address, - pub current_difficulty: U256, - pub current_gas_limit: u64, - pub current_number: u64, - pub current_timestamp: u64, - pub previous_hash: H256, -} - -#[derive(PartialEq, Eq, Default, Debug, Clone)] -pub struct AccountMatch { - pub address: Address, - pub balance: Option, - pub code: Option, - pub nonce: Option, - pub storage: HashMap, -} - -impl TryInto for AccountMatch { - type Error = anyhow::Error; - fn try_into(self) -> Result { - Ok(Account { - address: self.address, - balance: self.balance.context("balance")?, - code: self.code.context("code")?, - nonce: self.nonce.context("nonce")?, - storage: self.storage, - }) - } -} - -type StateTestResult = HashMap; - -#[derive(PartialEq, Clone, Eq, Debug)] -pub struct StateTest { - pub path: String, - pub id: String, - pub env: Env, - pub secret_key: Bytes, - pub from: Address, - pub to: Option
, - pub gas_limit: u64, - pub gas_price: U256, - pub nonce: U256, - pub value: U256, - pub data: Bytes, - pub pre: HashMap, - pub result: StateTestResult, - pub exception: bool, -} -impl std::fmt::Display for StateTest { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let max_len = 100; + if expected.nonce.map(|v| v == actual.nonce) == Some(false) { + return Err(StateTestError::NonceMismatch { + expected: expected.nonce.unwrap(), + found: actual.nonce, + }); + } - let format = |v: &str, k: &str| -> String { - let mut text = String::new(); - let k = if k.is_empty() { - k.to_string() + if let Some(expected_code) = &expected.code { + let actual_code = if actual.code_hash.is_zero() { + std::borrow::Cow::Owned(Vec::new()) } else { - format!("{} :", k) + std::borrow::Cow::Borrowed(&builder.code_db.0[&actual.code_hash]) }; - let max_len = max_len - k.len(); - for i in 0..=v.len() / max_len { - if i == 0 && !k.is_empty() { - text.push_str(&k); - } else { - let padding: String = " ".repeat(k.len()); - text.push_str(&padding); - } - text.push_str(&v[i * max_len..std::cmp::min((i + 1) * max_len, v.len())]); - text.push('\n'); - } - text - }; - - use prettytable::Table; - let mut table = Table::new(); - table.add_row(row!["id", self.id]); - table.add_row(row!["path", self.path]); - table.add_row(row!["coinbase", format!("{:?}", self.env.current_coinbase)]); - - table.add_row(row![ - "difficulty", - format!("{}", self.env.current_difficulty) - ]); - table.add_row(row!["number", format!("{}", self.env.current_number)]); - table.add_row(row!["timestamp", format!("{}", self.env.current_timestamp)]); - table.add_row(row!["prev_hash", format!("{:?}", self.env.previous_hash)]); - table.add_row(row!["sk", hex::encode(&self.secret_key)]); - table.add_row(row!["from", format!("{:?}", self.from)]); - table.add_row(row!["to", format!("{:?}", self.to)]); - table.add_row(row!["gas_limit", format!("{}", self.gas_limit)]); - table.add_row(row!["gas_price", format!("{}", self.gas_price)]); - table.add_row(row!["nonce", format!("{}", self.nonce)]); - table.add_row(row!["value", format!("{}", self.value)]); - table.add_row(row!["data", format(&hex::encode(&self.data), "")]); - table.add_row(row!["exception", self.exception]); - - let mut addrs: Vec<_> = self.pre.keys().collect(); - addrs.extend(self.result.keys()); - addrs.sort(); - addrs.dedup(); - for addr in addrs { - let mut state = HashMap::new(); - if let Some(pre) = self.pre.get(addr) { - state.insert("balance".to_string(), format!("{}", pre.balance)); - state.insert("nonce".to_string(), format!("{}", pre.nonce)); - state.insert("code".to_string(), hex::encode(&pre.code).to_string()); - for (key, value) in &pre.storage { - let (k, v) = (format!("slot {}", key), format!("{}", value)); - state.insert(k, v); - } - } - if let Some(result) = self.result.get(addr) { - let none = String::from("∅"); - if let Some(balance) = result.balance { - let pre = state.get("balance").unwrap_or(&none); - let text = format!("{} → {}", pre, balance); - state.insert("balance".to_string(), text); - } - if let Some(code) = &result.code { - let pre = state.get("code").unwrap_or(&none); - let text = format!("{} → {}", pre, code); - state.insert("code".to_string(), text); - } - if let Some(nonce) = &result.nonce { - let pre = state.get("nonce").unwrap_or(&none); - let text = format!("{} → {}", pre, nonce); - state.insert("nonce".to_string(), text); - } - for (key, value) in &result.storage { - let (k, v) = (format!("slot {}", key), format!("{}", value)); - let pre = state.get(&k).unwrap_or(&none); - let text = format!("{} → {}", pre, v); - state.insert(k, text); - } - } - let mut text = String::new(); - let mut keys: Vec<_> = state.keys().collect(); - keys.sort(); - for k in keys { - text.push_str(&format(state.get(k).unwrap(), k)); - } - table.add_row(row![format!("{:?}", addr), text]); - } - write!(f, "{}", table)?; - - Ok(()) - } -} - -impl StateTest { - fn into_traceconfig(self) -> (String, TraceConfig, StateTestResult) { - let chain_id = 1; - let wallet = LocalWallet::from_str(&hex::encode(self.secret_key.0)).unwrap(); - let mut tx = TransactionRequest::new() - .chain_id(chain_id) - .from(self.from) - .nonce(self.nonce) - .value(self.value) - .data(self.data.clone()) - .gas(self.gas_limit) - .gas_price(self.gas_price); - - if let Some(to) = self.to { - tx = tx.to(to); - } - - let sig = wallet.sign_transaction_sync(&tx.into()); - - ( - self.id, - TraceConfig { - chain_id: U256::one(), - history_hashes: Vec::new(), - block_constants: geth_types::BlockConstants { - coinbase: self.env.current_coinbase, - timestamp: U256::from(self.env.current_timestamp), - number: U64::from(self.env.current_number), - difficulty: self.env.current_difficulty, - gas_limit: U256::from(self.env.current_gas_limit), - base_fee: U256::one(), - }, - - transactions: vec![geth_types::Transaction { - from: self.from, - to: self.to, - nonce: self.nonce, - value: self.value, - gas_limit: U256::from(self.gas_limit), - gas_price: self.gas_price, - gas_fee_cap: U256::zero(), - gas_tip_cap: U256::zero(), - call_data: self.data, - access_list: None, - v: sig.v, - r: sig.r, - s: sig.s, - }], - accounts: self.pre, - ..Default::default() - }, - self.result, - ) - } - pub fn check_post( - builder: &CircuitInputBuilder, - post: &HashMap, - ) -> Result<(), StateTestError> { - // check if the generated account data is the expected one - for (address, expected) in post { - let (_, actual) = builder.sdb.get_account(address); - - if expected.balance.map(|v| v == actual.balance) == Some(false) { - return Err(StateTestError::BalanceMismatch { - expected: expected.balance.unwrap(), - found: actual.balance, + if &actual_code as &[u8] != expected_code.0 { + return Err(StateTestError::CodeMismatch { + expected: expected_code.clone(), + found: Bytes::from(actual_code.to_vec()), }); } - - if expected.nonce.map(|v| v == actual.nonce) == Some(false) { - return Err(StateTestError::NonceMismatch { - expected: expected.nonce.unwrap(), - found: actual.nonce, + } + for (slot, expected_value) in &expected.storage { + let actual_value = actual.storage.get(slot).cloned().unwrap_or_else(U256::zero); + if expected_value != &actual_value { + return Err(StateTestError::StorageMismatch { + slot: *slot, + expected: *expected_value, + found: actual_value, }); } - - if let Some(expected_code) = &expected.code { - let actual_code = if actual.code_hash.is_zero() { - std::borrow::Cow::Owned(Vec::new()) - } else { - std::borrow::Cow::Borrowed(&builder.code_db.0[&actual.code_hash]) - }; - if &actual_code as &[u8] != expected_code.0 { - return Err(StateTestError::CodeMismatch { - expected: expected_code.clone(), - found: Bytes::from(actual_code.to_vec()), - }); - } - } - for (slot, expected_value) in &expected.storage { - let actual_value = actual.storage.get(slot).cloned().unwrap_or_else(U256::zero); - if expected_value != &actual_value { - return Err(StateTestError::StorageMismatch { - slot: *slot, - expected: *expected_value, - found: actual_value, - }); - } - } } - Ok(()) } + Ok(()) +} - pub fn test_circuit( - self, - builder: &CircuitInputBuilder, - bytecode_test_config: BytecodeTestConfig, - ) { - // build a witness block from trace result - let block = - zkevm_circuits::evm_circuit::witness::block_convert(&builder.block, &builder.code_db); - - // finish requiered tests according to config using this witness block - zkevm_circuits::test_util::test_circuits_using_witness_block(block, bytecode_test_config) - .expect("circuit should pass"); - } - - pub fn geth_trace(self) -> Result { - let (_, trace_config, _) = self.into_traceconfig(); - - let mut geth_traces = external_tracer::trace(&trace_config) - .map_err(|err| StateTestError::CircuitInput(err.to_string()))?; - - Ok(geth_traces.remove(0)) +fn into_traceconfig(st: StateTest) -> (String, TraceConfig, StateTestResult) { + let chain_id = 1; + let wallet = LocalWallet::from_str(&hex::encode(st.secret_key.0)).unwrap(); + let mut tx = TransactionRequest::new() + .chain_id(chain_id) + .from(st.from) + .nonce(st.nonce) + .value(st.value) + .data(st.data.clone()) + .gas(st.gas_limit) + .gas_price(st.gas_price); + + if let Some(to) = st.to { + tx = tx.to(to); } + let tx: TypedTransaction = tx.into(); + + let sig = wallet.sign_transaction_sync(&tx); + + ( + st.id, + TraceConfig { + chain_id: U256::one(), + history_hashes: vec![U256::from_big_endian(st.env.previous_hash.as_bytes())], + block_constants: geth_types::BlockConstants { + coinbase: st.env.current_coinbase, + timestamp: U256::from(st.env.current_timestamp), + number: U64::from(st.env.current_number), + difficulty: st.env.current_difficulty, + gas_limit: U256::from(st.env.current_gas_limit), + base_fee: U256::one(), + }, - pub fn run(self, config: StateTestConfig) -> Result<(), StateTestError> { - // get the geth traces + transactions: vec![geth_types::Transaction { + from: st.from, + to: st.to, + nonce: U64::from(st.nonce), + value: st.value, + gas_limit: U64::from(st.gas_limit), + gas_price: st.gas_price, + gas_fee_cap: U256::zero(), + gas_tip_cap: U256::zero(), + call_data: st.data, + access_list: None, + v: sig.v, + r: sig.r, + s: sig.s, + }], + accounts: st.pre, + ..Default::default() + }, + st.result, + ) +} - let (_, trace_config, post) = self.clone().into_traceconfig(); +pub fn geth_trace(st: StateTest) -> Result { + let (_, trace_config, _) = into_traceconfig(st); - if self.to.is_none() { - return Err(StateTestError::SkipUnimplemented( - "TransactionCreation".to_string(), - )); - } + let mut geth_traces = external_tracer::trace(&trace_config) + .map_err(|err| StateTestError::CircuitInput(err.to_string()))?; - let geth_traces = external_tracer::trace(&trace_config); - if self.exception { - if geth_traces.is_ok() { - return Err(StateTestError::Exception { - expected: self.exception, - found: geth_traces.is_err(), - }); - } else { - return Ok(()); - } - } + Ok(geth_traces.remove(0)) +} - let geth_traces = - geth_traces.map_err(|err| StateTestError::CircuitInput(err.to_string()))?; +pub fn run_test( + st: StateTest, + suite: TestSuite, + circuits_config: CircuitsConfig, +) -> Result<(), StateTestError> { + // get the geth traces - if geth_traces[0].struct_logs.len() as u64 > config.global.max_steps { - return Err(StateTestError::SkipTestMaxSteps( - geth_traces[0].struct_logs.len(), - )); - } + let (_, trace_config, post) = into_traceconfig(st.clone()); - // we are not checking here geth_traces[0].failed, since - // there are some tests that makes the tx failing - // (eg memory filler tests) - - if let Some(step) = geth_traces[0] - .struct_logs - .iter() - .find(|step| config.global.unimplemented_opcodes.contains(&step.op)) - { - return Err(StateTestError::SkipUnimplemented(format!( - "OPCODE {:?}", - step.op - ))); - } + let geth_traces = external_tracer::trace(&trace_config); - for err in [EVMERR_STACKUNDERFLOW, EVMERR_OOG, EVMERR_GAS_UINT64OVERFLOW] { - if geth_traces[0] - .struct_logs - .iter() - .any(|step| step.error.as_ref().map(|e| e.contains(err)) == Some(true)) - { - return Err(StateTestError::SkipUnimplemented(format!("Error {}", err))); - } - } - - if geth_traces[0].gas.0 > config.global.max_gas { - return Err(StateTestError::SkipTestMaxGasLimit(geth_traces[0].gas.0)); + let geth_traces = match (geth_traces, st.exception) { + (Ok(res), false) => res, + (Ok(_), true) => { + return Err(StateTestError::Exception { + expected: true, + found: "no error".into(), + }) } - - if let Some(acc) = self.pre.get(&self.to.unwrap()) { - if acc.code.0.is_empty() { - return Err(StateTestError::SkipUnimplemented( - "Calling to empty accounts unimplemented (1)".to_string(), - )); - } - } else { - return Err(StateTestError::SkipUnimplemented( - "Calling to empty accounts unimplemented (2)".to_string(), - )); + (Err(_), true) => return Ok(()), + (Err(err), false) => { + return Err(StateTestError::Exception { + expected: false, + found: err.to_string(), + }) } + }; - let builder = Self::create_input_builder(trace_config, geth_traces)?; - - Self::check_post(&builder, &post)?; - - if config.run_circuit { - Self::test_circuit(self, &builder, config.bytecode_test_config); - } - Ok(()) + if geth_traces[0].struct_logs.len() as u64 > suite.max_steps { + return Err(StateTestError::SkipTestMaxSteps( + geth_traces[0].struct_logs.len(), + )); } - fn create_input_builder( - trace_config: TraceConfig, - geth_traces: Vec, - ) -> Result { - let transactions = trace_config - .transactions - .into_iter() - .enumerate() - .map(|(index, tx)| eth_types::Transaction { - from: tx.from, - to: tx.to, - value: tx.value, - input: tx.call_data, - gas_price: Some(tx.gas_price), - access_list: tx.access_list, - nonce: tx.nonce, - gas: tx.gas_limit, - transaction_index: Some(U64::from(index)), - ..eth_types::Transaction::default() - }) - .collect(); - - let eth_block = eth_types::Block { - author: Some(trace_config.block_constants.coinbase), - timestamp: trace_config.block_constants.timestamp, - number: Some(U64::from(trace_config.block_constants.number.as_u64())), - difficulty: trace_config.block_constants.difficulty, - gas_limit: trace_config.block_constants.gas_limit, - base_fee_per_gas: Some(trace_config.block_constants.base_fee), - transactions, - ..eth_types::Block::default() - }; + if suite.max_gas > 0 && geth_traces[0].gas.0 > suite.max_gas { + return Err(StateTestError::SkipTestMaxGasLimit(geth_traces[0].gas.0)); + } - // process the transaction - let geth_data = eth_types::geth_types::GethData { - chain_id: trace_config.chain_id, - history_hashes: trace_config.history_hashes.clone(), - geth_traces: geth_traces.clone(), - accounts: trace_config.accounts.values().cloned().collect(), - eth_block: eth_block.clone(), + let transactions = trace_config + .transactions + .into_iter() + .enumerate() + .map(|(index, tx)| { + tx.to_response( + U64::from(index), + trace_config.chain_id, + trace_config.block_constants.number, + ) + }) + .collect(); + + let eth_block = eth_types::Block { + author: Some(trace_config.block_constants.coinbase), + timestamp: trace_config.block_constants.timestamp, + number: Some(U64::from(trace_config.block_constants.number.as_u64())), + difficulty: trace_config.block_constants.difficulty, + gas_limit: trace_config.block_constants.gas_limit, + base_fee_per_gas: Some(trace_config.block_constants.base_fee), + transactions, + ..eth_types::Block::default() + }; + + let wallet: LocalWallet = SigningKey::from_bytes(&st.secret_key).unwrap().into(); + let mut wallets = HashMap::new(); + wallets.insert( + wallet.address(), + wallet.with_chain_id(trace_config.chain_id.as_u64()), + ); + + // process the transaction + let mut geth_data = eth_types::geth_types::GethData { + chain_id: trace_config.chain_id, + history_hashes: trace_config.history_hashes.clone(), + geth_traces: geth_traces.clone(), + accounts: trace_config.accounts.values().cloned().collect(), + eth_block: eth_block.clone(), + }; + + let mut builder; + + if !circuits_config.super_circuit { + let circuits_params = CircuitsParams { + max_txs: 1, + max_rws: 55000, + max_calldata: 5000, + max_bytecode: 5000, + max_copy_rows: 55000, + max_evm_rows: 0, + max_exp_steps: 5000, + max_keccak_rows: 0, }; + let block_data = BlockData::new_from_geth_data_with_params(geth_data, circuits_params); - let block_data = BlockData::new_from_geth_data(geth_data); - let mut builder = block_data.new_circuit_input_builder(); + builder = block_data.new_circuit_input_builder(); builder .handle_block(ð_block, &geth_traces) .map_err(|err| StateTestError::CircuitInput(err.to_string()))?; - Ok(builder) - } + let block: Block = + zkevm_circuits::evm_circuit::witness::block_convert(&builder.block, &builder.code_db) + .unwrap(); + + CircuitTestBuilder::<1, 1>::new_from_block(block).run(); + } else { + geth_data.sign(&wallets); + + let circuits_params = CircuitsParams { + max_txs: 1, + max_calldata: 32, + max_rws: 256, + max_copy_rows: 256, + max_exp_steps: 256, + max_bytecode: 512, + max_evm_rows: 0, + max_keccak_rows: 0, + }; + let (k, circuit, instance, _builder) = + SuperCircuit::::build(geth_data, circuits_params, Fr::from(0x100)).unwrap(); + builder = _builder; + + let prover = MockProver::run(k, &circuit, instance).unwrap(); + prover.assert_satisfied_par(); + }; + + check_post(&builder, &post)?; + + Ok(()) } diff --git a/testool/src/statetest/json.rs b/testool/src/statetest/json.rs index 09bbbd7cca..7bd35e26b7 100644 --- a/testool/src/statetest/json.rs +++ b/testool/src/statetest/json.rs @@ -1,20 +1,13 @@ -#![allow(dead_code, unused_imports)] - -use super::executor::{AccountMatch, Env, StateTest}; -use crate::abi; -use crate::compiler::Compiler; -use crate::utils::MainnetFork; -use anyhow::{bail, Context, Result}; -use eth_types::evm_types::OpcodeId; -use eth_types::{geth_types::Account, Address, Bytes, H256, U256}; -use ethers_core::k256::ecdsa::SigningKey; -use ethers_core::utils::secret_key_to_address; +use super::{ + parse, + spec::{AccountMatch, Env, StateTest}, +}; +use crate::{compiler::Compiler, utils::MainnetFork}; +use anyhow::{bail, Result}; +use eth_types::{geth_types::Account, Address, U256}; +use ethers_core::{k256::ecdsa::SigningKey, utils::secret_key_to_address}; use serde::Deserialize; use std::collections::HashMap; -use std::convert::TryInto; -use std::ops::RangeBounds; -use std::str::FromStr; -use yaml_rust::Yaml; #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] @@ -40,7 +33,6 @@ struct AccountPost { code: Option, nonce: Option, storage: Option>, - shouldnotexist: Option, } #[derive(Debug, Clone, Deserialize)] @@ -113,31 +105,31 @@ impl<'a> JsonStateTestBuilder<'a> { let env = Self::parse_env(&test.env)?; let pre = self.parse_accounts_pre(&test.pre)?; - let to = Self::parse_to_address(&test.transaction.to)?; - let secret_key = Self::parse_bytes(&test.transaction.secret_key)?; + let to = parse::parse_to_address(&test.transaction.to)?; + let secret_key = parse::parse_bytes(&test.transaction.secret_key)?; let from = secret_key_to_address(&SigningKey::from_bytes(&secret_key.to_vec())?); - let nonce = Self::parse_u256(&test.transaction.nonce)?; - let gas_price = Self::parse_u256(&test.transaction.gas_price)?; + let nonce = parse::parse_u64(&test.transaction.nonce)?; + let gas_price = parse::parse_u256(&test.transaction.gas_price)?; let data_s: Vec<_> = test .transaction .data .iter() - .map(|item| self.parse_calldata(item)) + .map(|item| parse::parse_calldata(self.compiler, item)) .collect::>()?; let gas_limit_s: Vec<_> = test .transaction .gas_limit .iter() - .map(|item| Self::parse_u64(item)) + .map(|item| parse::parse_u64(item)) .collect::>()?; let value_s: Vec<_> = test .transaction .value .iter() - .map(|item| Self::parse_u256(item)) + .map(|item| parse::parse_u256(item)) .collect::>()?; let mut expects = Vec::new(); @@ -184,8 +176,8 @@ impl<'a> JsonStateTestBuilder<'a> { gas_price, gas_limit: *gas_limit, value: *value, - data: eth_types::Bytes(data.0.clone()), - exception: false, // TODO: check + data: data.0.clone(), + exception: false, }); } } @@ -199,12 +191,12 @@ impl<'a> JsonStateTestBuilder<'a> { /// parse env section fn parse_env(env: &TestEnv) -> Result { Ok(Env { - current_coinbase: Self::parse_address(&env.current_coinbase)?, - current_difficulty: Self::parse_u256(&env.current_difficulty)?, - current_gas_limit: Self::parse_u64(&env.current_gas_limit)?, - current_number: Self::parse_u64(&env.current_number)?, - current_timestamp: Self::parse_u64(&env.current_timestamp)?, - previous_hash: Self::parse_hash(&env.previous_hash)?, + current_coinbase: parse::parse_address(&env.current_coinbase)?, + current_difficulty: parse::parse_u256(&env.current_difficulty)?, + current_gas_limit: parse::parse_u64(&env.current_gas_limit)?, + current_number: parse::parse_u64(&env.current_number)?, + current_timestamp: parse::parse_u64(&env.current_timestamp)?, + previous_hash: parse::parse_hash(&env.previous_hash)?, }) } @@ -215,16 +207,16 @@ impl<'a> JsonStateTestBuilder<'a> { ) -> Result> { let mut accounts = HashMap::new(); for (address, acc) in accounts_pre { - let address = Self::parse_address(address)?; + let address = parse::parse_address(address)?; let mut storage = HashMap::new(); for (k, v) in &acc.storage { - storage.insert(Self::parse_u256(k)?, Self::parse_u256(v)?); + storage.insert(parse::parse_u256(k)?, parse::parse_u256(v)?); } let account = Account { address, - balance: Self::parse_u256(&acc.balance)?, - nonce: Self::parse_u256(&acc.nonce)?, - code: self.parse_code(&acc.code)?, + balance: parse::parse_u256(&acc.balance)?, + nonce: parse::parse_u64(&acc.nonce)?.into(), + code: parse::parse_code(self.compiler, &acc.code)?, storage, }; accounts.insert(address, account); @@ -239,11 +231,11 @@ impl<'a> JsonStateTestBuilder<'a> { ) -> Result> { let mut accounts = HashMap::new(); for (address, acc) in accounts_post { - let address = Self::parse_address(address)?; + let address = parse::parse_address(address)?; let mut storage: HashMap = HashMap::new(); if let Some(acc_storage) = &acc.storage { for (k, v) in acc_storage { - storage.insert(Self::parse_u256(k)?, Self::parse_u256(v)?); + storage.insert(parse::parse_u256(k)?, parse::parse_u256(v)?); } } let account = AccountMatch { @@ -251,13 +243,17 @@ impl<'a> JsonStateTestBuilder<'a> { balance: acc .balance .as_ref() - .map(|v| Self::parse_u256(v)) + .map(|v| parse::parse_u256(v)) + .transpose()?, + code: acc + .code + .as_ref() + .map(|v| parse::parse_code(self.compiler, v)) .transpose()?, - code: acc.code.as_ref().map(|v| self.parse_code(v)).transpose()?, nonce: acc .nonce .as_ref() - .map(|v| Self::parse_u256(v)) + .map(|v| parse::parse_u64(v)) .transpose()?, storage, }; @@ -266,168 +262,6 @@ impl<'a> JsonStateTestBuilder<'a> { Ok(accounts) } - /// converts list of tagged values string into a map - /// if there's no tags, an entry with an empty tag and the full string is - /// returned - fn decompose_tags(expr: &str) -> HashMap { - let mut tags = HashMap::new(); - let mut it = expr.trim(); - if it.is_empty() { - tags.insert("".to_string(), "".to_string()); - } else { - while !it.is_empty() { - if it.starts_with(':') { - let tag = &it[..it.find(&[' ', '\n']).expect("unable to find end tag")]; - it = &it[tag.len() + 1..]; - let value_len = if tag == ":yul" || tag == ":solidity" || tag == ":asm" { - it.len() - } else { - it.find(':').unwrap_or(it.len()) - }; - tags.insert(tag.to_string(), it[..value_len].trim().to_string()); - it = &it[value_len..]; - } else { - tags.insert("".to_string(), it.trim().to_string()); - it = &it[it.len()..] - } - } - } - tags - } - /// returns the element as an address - fn parse_address(as_str: &str) -> Result
{ - if let Some(hex) = as_str.strip_prefix("0x") { - Ok(Address::from_slice( - &hex::decode(hex).context("parse_address")?, - )) - } else { - Ok(Address::from_slice( - &hex::decode(as_str).context("parse_address")?, - )) - } - } - - /// returns the element as a to address - fn parse_to_address(as_str: &str) -> Result> { - if as_str.trim().is_empty() { - return Ok(None); - } - Self::parse_address(as_str).map(|x| Ok(Some(x)))? - } - - /// returns the element as an array of bytes - fn parse_bytes(as_str: &str) -> Result { - if let Some(hex) = as_str.strip_prefix("0x") { - Ok(Bytes::from(hex::decode(hex).context("parse_bytes")?)) - } else { - Ok(Bytes::from(hex::decode(as_str).context("parse_bytes")?)) - } - } - - /// parse entry as code, can be 0x, :raw or { LLL } - fn parse_code(&mut self, as_str: &str) -> Result { - let tags = Self::decompose_tags(as_str); - - let mut code = if let Some(notag) = tags.get("") { - if notag.starts_with("0x") { - Bytes::from(hex::decode(&tags[""][2..]).context("parse_code")?) - } else if notag.starts_with('{') { - self.compiler.lll(notag)? - } else if notag.trim().is_empty() { - Bytes::default() - } else { - bail!( - "do not know what to do with code(1) {:?} '{}'", - as_str, - notag - ); - } - } else if let Some(raw) = tags.get(":raw") { - Bytes::from(hex::decode(&raw[2..])?) - } else if let Some(yul) = tags.get(":yul") { - self.compiler.yul(yul)? - } else if let Some(solidity) = tags.get(":solidity") { - self.compiler.solidity(solidity)? - } else if let Some(asm) = tags.get(":asm") { - self.compiler.asm(asm)? - } else { - bail!("do not know what to do with code(2) '{:?}'", as_str); - }; - - // TODO: remote the finish with STOP if does not finish with it when fixed - if !code.0.is_empty() && code.0[code.0.len() - 1] != OpcodeId::STOP.as_u8() { - let mut code_stop = Vec::new(); - code_stop.extend_from_slice(&code.0); - code_stop.push(OpcodeId::STOP.as_u8()); - code = Bytes::from(code_stop); - } - - Ok(code) - } - - /// returns the element as calldata bytes, supports :raw and :abi - fn parse_calldata(&mut self, as_str: &str) -> Result { - let tags = Self::decompose_tags(as_str); - - if let Some(notag) = tags.get("") { - let notag = notag.trim(); - if notag.is_empty() { - Ok(Bytes::default()) - } else if notag.starts_with('{') { - Ok(self.compiler.lll(notag)?) - } else if let Some(hex) = notag.strip_prefix("0x") { - Ok(Bytes::from(hex::decode(hex)?)) - } else { - bail!("do not know what to do with calldata (1): '{:?}'", as_str); - } - } else if let Some(raw) = tags.get(":raw") { - Ok(Bytes::from(hex::decode(&raw[2..])?)) - } else if let Some(abi) = tags.get(":abi") { - Ok(abi::encode_funccall(abi)?) - } else if let Some(yul) = tags.get(":yul") { - Ok(self.compiler.yul(yul)?) - } else { - bail!( - "do not know what to do with calldata: (2) {:?} '{:?}'", - tags, - as_str - ) - } - } - - /// parse a hash entry - fn parse_hash(value: &str) -> Result { - if let Some(hex) = value.strip_prefix("0x") { - Ok(H256::from_slice(&hex::decode(hex).context("parse_hash")?)) - } else { - Ok(H256::from_slice(&hex::decode(value).context("parse_hash")?)) - } - } - - /// parse an uint256 entry - fn parse_u256(as_str: &str) -> Result { - if let Some(stripped) = as_str.strip_prefix("0x") { - Ok(U256::from_str_radix(stripped, 16)?) - } else if as_str - .to_lowercase() - .contains(['a', 'b', 'c', 'd', 'e', 'f']) - { - Ok(U256::from_str_radix(as_str, 16)?) - } else { - Ok(U256::from_str_radix(as_str, 10)?) - } - } - - /// parse u64 entry - #[allow(clippy::cast_sign_loss)] - fn parse_u64(as_str: &str) -> Result { - if let Some(stripped) = as_str.strip_prefix("0x") { - Ok(U256::from_str_radix(stripped, 16)?.as_u64()) - } else { - Ok(U256::from_str_radix(as_str, 10)?.as_u64()) - } - } - /// parse a unique or a list of references, /// -1 => Ref::Any /// a int value => Ref::Index(value) @@ -460,6 +294,8 @@ impl<'a> JsonStateTestBuilder<'a> { #[cfg(test)] mod test { use super::*; + use eth_types::{Bytes, H256}; + use std::{collections::HashMap, str::FromStr}; const JSON: &str = r#" { @@ -552,24 +388,23 @@ mod test { )?), gas_limit: 400000, gas_price: U256::from(10u64), - nonce: U256::from(0u64), + nonce: 0, value: U256::from(100000u64), data: Bytes::from(hex::decode("6001")?), pre: HashMap::from([( acc095e, Account { address: acc095e, - nonce: U256::from(0u64), balance: U256::from(1000000000000000000u64), code: Bytes::from(hex::decode("600160010160005500")?), - storage: HashMap::new(), + ..Default::default() }, )]), result: HashMap::from([( acc095e, AccountMatch { address: acc095e, - nonce: Some(U256::from(1u64)), + nonce: Some(1u64), balance: None, code: Some(Bytes::from(hex::decode("600160010160005500")?)), storage: HashMap::from([(U256::zero(), U256::from(2u64))]), diff --git a/testool/src/statetest/mod.rs b/testool/src/statetest/mod.rs index 0581ff9feb..258645aa05 100644 --- a/testool/src/statetest/mod.rs +++ b/testool/src/statetest/mod.rs @@ -1,11 +1,14 @@ mod executor; mod json; +mod parse; mod results; +pub mod spec; mod suite; mod yaml; -pub use executor::{StateTest, StateTestConfig, StateTestError}; +pub use executor::{geth_trace, run_test, CircuitsConfig, StateTestError}; pub use json::JsonStateTestBuilder; -pub use results::Results; +pub use results::{ResultLevel, Results}; +pub use spec::{AccountMatch, Env, StateTest, StateTestResult}; pub use suite::{load_statetests_suite, run_statetests_suite}; pub use yaml::YamlStateTestBuilder; diff --git a/testool/src/statetest/parse.rs b/testool/src/statetest/parse.rs new file mode 100644 index 0000000000..2cd2d32a4e --- /dev/null +++ b/testool/src/statetest/parse.rs @@ -0,0 +1,164 @@ +use std::collections::HashMap; + +use crate::{abi, Compiler}; + +use anyhow::{bail, Context, Result}; +use eth_types::{Address, Bytes, H256, U256}; +use log::debug; + +type Label = String; + +/// returns the element as an address +pub fn parse_address(as_str: &str) -> Result
{ + let hex = as_str.strip_prefix("0x").unwrap_or(as_str); + Ok(Address::from_slice( + &hex::decode(hex).context("parse_address")?, + )) +} + +/// returns the element as a to address +pub fn parse_to_address(as_str: &str) -> Result> { + if as_str.trim().is_empty() { + return Ok(None); + } + parse_address(as_str).map(|x| Ok(Some(x)))? +} + +/// returns the element as an array of bytes +pub fn parse_bytes(as_str: &str) -> Result { + let hex = as_str.strip_prefix("0x").unwrap_or(as_str); + Ok(Bytes::from(hex::decode(hex).context("parse_bytes")?)) +} + +/// converts list of tagged values string into a map +/// if there's no tags, an entry with an empty tag and the full string is +/// returned +fn decompose_tags(expr: &str) -> HashMap { + let mut tags = HashMap::new(); + let mut it = expr.trim(); + if it.is_empty() { + tags.insert("".to_string(), "".to_string()); + } else { + while !it.is_empty() { + if it.starts_with(':') { + let tag = &it[..it.find([' ', '\n']).expect("unable to find end tag")]; + it = &it[tag.len() + 1..]; + let value_len = if tag == ":yul" || tag == ":solidity" || tag == ":asm" { + it.len() + } else { + it.find(':').unwrap_or(it.len()) + }; + tags.insert(tag.to_string(), it[..value_len].trim().to_string()); + it = &it[value_len..]; + } else { + tags.insert("".to_string(), it.trim().to_string()); + it = &it[it.len()..] + } + } + } + tags +} + +/// returns the element as calldata bytes, supports 0x, :raw, :abi, :yul and +/// { LLL } +pub fn parse_calldata(compiler: &mut Compiler, as_str: &str) -> Result<(Bytes, Option