From b61f41d8ab34610fd430fa1062c769690c50d87a Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Thu, 21 Mar 2024 18:17:57 +0000 Subject: [PATCH 01/13] initial next easy private token easy private voting import test parent contract child --- .../writing_private_voting_contract.md | 6 +- .../aztec-nr/aztec/src/context/avm_context.nr | 8 +- .../aztec-nr/aztec/src/note/note_getter.nr | 16 +- .../contracts/avm_test_contract/src/main.nr | 36 +-- .../contracts/child_contract/src/main.nr | 30 +-- .../contracts/delegator_contract/src/main.nr | 18 +- .../easy_private_token_contract/src/main.nr | 2 +- .../easy_private_voting_contract/src/main.nr | 8 +- .../contracts/fpc_contract/src/main.nr | 4 +- .../import_test_contract/src/main.nr | 6 +- .../contracts/lending_contract/src/main.nr | 4 +- .../contracts/parent_contract/src/main.nr | 220 +++++++++--------- .../contracts/price_feed_contract/src/main.nr | 4 +- .../contracts/test_contract/src/main.nr | 4 +- .../token_bridge_contract/src/main.nr | 8 +- .../token_portal_content_hash_lib/src/lib.nr | 6 +- .../uniswap_contract/src/interfaces.nr | 4 +- .../crates/rollup-lib/src/components.nr | 20 +- .../types/src/merkle_tree/append_only_tree.nr | 26 +-- yarn-project/aztec.js/README.md | 2 +- .../end-to-end/src/docs_examples.test.ts | 2 +- .../end-to-end/src/e2e_2_pxes.test.ts | 2 +- .../src/e2e_account_contracts.test.ts | 2 +- .../src/e2e_nested_contract.test.ts | 34 +-- .../end-to-end/src/e2e_ordering.test.ts | 20 +- .../end-to-end/src/e2e_static_calls.test.ts | 24 +- .../src/client/private_execution.test.ts | 6 +- .../simulator/src/public/index.test.ts | 2 +- 28 files changed, 262 insertions(+), 262 deletions(-) diff --git a/docs/docs/developers/tutorials/writing_private_voting_contract.md b/docs/docs/developers/tutorials/writing_private_voting_contract.md index f64a16526e8a..685b89a9412b 100644 --- a/docs/docs/developers/tutorials/writing_private_voting_contract.md +++ b/docs/docs/developers/tutorials/writing_private_voting_contract.md @@ -89,7 +89,7 @@ In this contract, we will store three vars: 1. admin, as an Aztec address held in public state 2. tally, as a map with key as the persona and value as the number (in Field) held in public state -3. voteEnded, as a boolean held in public state +3. vote_ended, as a boolean held in public state ## Constructor @@ -97,7 +97,7 @@ The next step is to initialize the contract with a constructor. The constructor #include_code constructor noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr rust -This function takes the admin argument and writes it to the storage. We are also using this function to set the `voteEnded` boolean as false in the same way. +This function takes the admin argument and writes it to the storage. We are also using this function to set the `vote_ended` boolean as false in the same way. ## Casting a vote privately @@ -125,7 +125,7 @@ Create this new public function like this: The first thing we do here is assert that the vote has not ended. -`assert()` takes two arguments: the assertion, in this case that `storage.voteEnded` is not false, and the error thrown if the assertion fails. +`assert()` takes two arguments: the assertion, in this case that `storage.vote_ended` is not false, and the error thrown if the assertion fails. The code after the assertion will only run if the assertion is true. In this snippet, we read the current vote tally at the voteId, add 1 to it, and write this new number to the voteId. The `Field` element allows us to use `+` to add to an integer. diff --git a/noir-projects/aztec-nr/aztec/src/context/avm_context.nr b/noir-projects/aztec-nr/aztec/src/context/avm_context.nr index 803d1e92935e..998d96e5996a 100644 --- a/noir-projects/aztec-nr/aztec/src/context/avm_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/avm_context.nr @@ -129,11 +129,11 @@ impl PublicContextInterface for AVMContext { args, temporary_function_selector.to_field() ); - let returnData: [Field; RETURN_VALUES_LENGTH] = results.0; + let data_to_return: [Field; RETURN_VALUES_LENGTH] = results.0; let success: u8 = results.1; assert(success == 1, "Nested call failed!"); - returnData + data_to_return } fn static_call_public_function( @@ -144,7 +144,7 @@ impl PublicContextInterface for AVMContext { ) -> [Field; RETURN_VALUES_LENGTH] { let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; - let (returnData, success): ([Field; RETURN_VALUES_LENGTH], u8) = call_static( + let (data_to_return, success): ([Field; RETURN_VALUES_LENGTH], u8) = call_static( gas, contract_address, args, @@ -152,7 +152,7 @@ impl PublicContextInterface for AVMContext { ); assert(success == 1, "Nested static call failed!"); - returnData + data_to_return } fn delegate_call_public_function( diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr index 679f097ee656..51ba35cecc93 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -43,21 +43,21 @@ fn check_note_fields(serialized_note: [Field; N], selects: BoundedVec pub Field { + fn raw_nested_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field(); let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; // Nested call - let results = context.call_public_function_raw(gas, context.this_address(), selector, [argA, argB]); - let returnData: [Field; 1] = results.0; + let results = context.call_public_function_raw(gas, context.this_address(), selector, [arg_a, arg_b]); + let data_to_return: [Field; 1] = results.0; // this explicit size ^ is necessary to ensure that retSize is compile-time - // (ensure the returnData is in a HeapArray not a HeapVector) + // (ensure the data_to_return is in a HeapArray not a HeapVector) let success: u8 = results.1; assert(success == 1, "Call failed"); - let addResult = returnData[0]; - addResult + let add_result = data_to_return[0]; + add_result } // Use the `call_public_function` wrapper to initiate a nested call to the add function #[aztec(public-vm)] - fn nested_call_to_add(argA: Field, argB: Field) -> pub Field { + fn nested_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)"); // Nested call using standard context interface function - let returnData: [Field; RETURN_VALUES_LENGTH] = context.call_public_function(context.this_address(), selector, [argA, argB]); + let data_to_return: [Field; RETURN_VALUES_LENGTH] = context.call_public_function(context.this_address(), selector, [arg_a, arg_b]); // this explicit size ^ is necessary to ensure that retSize is compile-time - // (ensure the returnData is in a HeapArray not a HeapVector) + // (ensure the data_to_return is in a HeapArray not a HeapVector) - let addResult = returnData[0]; - addResult + let add_result = data_to_return[0]; + add_result } // Directly call_static the external call opcode to initiate a nested call to the add function #[aztec(public-vm)] - fn raw_nested_static_call_to_add(argA: Field, argB: Field) -> pub (Field, u8) { + fn raw_nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub (Field, u8) { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field(); let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; - let (resultData, success): ([Field; 1], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, [argA, argB]); + let (result_data, success): ([Field; 1], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, [arg_a, arg_b]); - (resultData[0], success) + (result_data[0], success) } // Directly call_static `set_storage_single`. Should fail since it's accessing storage. @@ -340,19 +340,19 @@ contract AvmTest { let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; let calldata: [Field; 1] = [20]; - let (_returnData, success): ([Field; 0], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, calldata); + let (_data_to_return, success): ([Field; 0], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, calldata); success } // Indirectly call_static the external call opcode to initiate a nested call to the add function #[aztec(public-vm)] - fn nested_static_call_to_add(argA: Field, argB: Field) -> pub Field { + fn nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)"); - let resultData: [Field; RETURN_VALUES_LENGTH] = context.static_call_public_function(context.this_address(), selector, [argA, argB]); + let result_data: [Field; RETURN_VALUES_LENGTH] = context.static_call_public_function(context.this_address(), selector, [arg_a, arg_b]); - resultData[0] + result_data[0] } // Indirectly call_static `set_storage_single`. Should revert since it's accessing storage. diff --git a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr index 101a96a066af..e9fdcc07ad80 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr @@ -22,25 +22,25 @@ contract Child { // Can only be called from this contract. #[aztec(private)] #[aztec(internal)] - fn valueInternal(input: Field) -> Field { + fn value_internal(input: Field) -> Field { input + context.chain_id() + context.version() } // Returns base_value + chain_id + version + block_number + timestamp #[aztec(public)] - fn pubGetValue(base_value: Field) -> Field { - let returnValue = base_value + fn pub_get_value(base_value: Field) -> Field { + let return_value = base_value + context.chain_id() + context.version() + context.block_number() + context.timestamp(); - returnValue + return_value } // Sets `current_value` to `new_value` #[aztec(public)] - fn pubSetValue(new_value: Field) -> Field { + fn pub_set_value(new_value: Field) -> Field { storage.current_value.write(new_value); emit_unencrypted_log(&mut context, new_value); @@ -48,14 +48,14 @@ contract Child { } #[aztec(private)] - fn privateSetValue(new_value: Field, owner: AztecAddress) -> Field { + fn private_set_value(new_value: Field, owner: AztecAddress) -> Field { let mut note = ValueNote::new(new_value, owner); storage.a_private_value.insert(&mut note, true); new_value } #[aztec(private)] - fn privateGetValue(amount: Field, owner: AztecAddress) -> Field { + fn private_get_value(amount: Field, owner: AztecAddress) -> Field { let options = NoteGetterOptions::new().select(ValueNote::properties().value, amount, Option::none()).select( ValueNote::properties().owner, owner.to_field(), @@ -67,7 +67,7 @@ contract Child { // Increments `current_value` by `new_value` #[aztec(public)] - fn pubIncValue(new_value: Field) -> Field { + fn pub_inc_value(new_value: Field) -> Field { let old_value = storage.current_value.read(); storage.current_value.write(old_value + new_value); emit_unencrypted_log(&mut context, new_value); @@ -78,7 +78,7 @@ contract Child { // Increments `current_value` by `new_value`. Can only be called from this contract. #[aztec(public)] #[aztec(internal)] - fn pubIncValueInternal(new_value: Field) -> Field { + fn pub_inc_value_internal(new_value: Field) -> Field { let old_value = storage.current_value.read(); storage.current_value.write(old_value + new_value); emit_unencrypted_log(&mut context, new_value); @@ -87,20 +87,20 @@ contract Child { } #[aztec(public)] - fn setValueTwiceWithNestedFirst() { - let pubSetValueSelector = FunctionSelector::from_signature("pubSetValue(Field)"); - let _ret = context.call_public_function(context.this_address(), pubSetValueSelector, [10]); + fn set_value_twice_with_nested_first() { + let pub_set_value_selector = FunctionSelector::from_signature("pub_set_value(Field)"); + let _ret = context.call_public_function(context.this_address(), pub_set_value_selector, [10]); storage.current_value.write(20); emit_unencrypted_log(&mut context, 20); } #[aztec(public)] - fn setValueTwiceWithNestedLast() { + fn set_value_twice_with_nested_last() { storage.current_value.write(20); emit_unencrypted_log(&mut context, 20); - let pubSetValueSelector = FunctionSelector::from_signature("pubSetValue(Field)"); - let _ret = context.call_public_function(context.this_address(), pubSetValueSelector, [10]); + let pub_set_value_selector = FunctionSelector::from_signature("pub_set_value(Field)"); + let _ret = context.call_public_function(context.this_address(), pub_set_value_selector, [10]); } } diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr index 14751ae81025..46417912fa17 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr @@ -13,32 +13,32 @@ contract Delegator { #[aztec(private)] fn private_delegate_set_value( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 2] ) { // Call the target private function - let return_values = context.delegate_call_private_function(targetContract, targetSelector, args); + let return_values = context.delegate_call_private_function(target_contract, target_selector, args); // Copy the return value from the call to this function's return values return_values[0] } #[aztec(private)] fn enqueued_delegate_set_value( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) { - context.delegate_call_public_function(targetContract, targetSelector, args); + context.delegate_call_public_function(target_contract, target_selector, args); } #[aztec(public)] fn public_delegate_set_value( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) { - let _ = context.delegate_call_public_function(targetContract, targetSelector, args); + let _ = context.delegate_call_public_function(target_contract, target_selector, args); } unconstrained fn view_private_value(amount: Field, owner: AztecAddress) -> pub Field { diff --git a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr index 12261322cf0e..6d398f9fb2ae 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr @@ -37,7 +37,7 @@ contract EasyPrivateToken { } // Helper function to get the balance of a user ("unconstrained" is a Noir alternative of Solidity's "view" function). - unconstrained fn getBalance(owner: AztecAddress) -> pub Field { + unconstrained fn get_balance(owner: AztecAddress) -> pub Field { let balances = storage.balances; // Return the sum of all notes in the set. diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr index 8417feced27a..ddcfcb3bcc9b 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr @@ -10,7 +10,7 @@ contract EasyPrivateVoting { struct Storage { admin: PublicMutable, // admin can end vote tally: Map>, // we will store candidate as key and number of votes as value - voteEnded: PublicMutable, // voteEnded is boolean + vote_ended: PublicMutable, // vote_ended is boolean } // docs:end:storage_struct @@ -19,7 +19,7 @@ contract EasyPrivateVoting { #[aztec(initializer)] // annotation to mark function as a constructor fn constructor(admin: AztecAddress) { storage.admin.write(admin); - storage.voteEnded.write(false); + storage.vote_ended.write(false); } // docs:end:constructor @@ -41,7 +41,7 @@ contract EasyPrivateVoting { #[aztec(public)] #[aztec(internal)] fn add_to_tally_public(candidate: Field) { - assert(storage.voteEnded.read() == false, "Vote has ended"); // assert that vote has not ended + assert(storage.vote_ended.read() == false, "Vote has ended"); // assert that vote has not ended let new_tally = storage.tally.at(candidate).read() + 1; storage.tally.at(candidate).write(new_tally); } @@ -51,7 +51,7 @@ contract EasyPrivateVoting { #[aztec(public)] fn end_vote() { assert(storage.admin.read().eq(context.msg_sender()), "Only admin can end votes"); // assert that caller is admin - storage.voteEnded.write(true); + storage.vote_ended.write(true); } // docs:end:end_vote // docs:start:get_vote diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr index 476b2bdbd671..da3f517b69a2 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr @@ -73,13 +73,13 @@ contract FPC { #[aztec(public)] #[aztec(internal)] - fn pay_fee_with_shielded_rebate(amount: Field, asset: AztecAddress, secretHash: Field) { + fn pay_fee_with_shielded_rebate(amount: Field, asset: AztecAddress, secret_hash: Field) { let refund = context.call_public_function( storage.gas_token_address.read_public(), FunctionSelector::from_signature("pay_fee(Field)"), [amount] )[0]; - Token::at(asset).shield(&mut context, context.this_address(), refund, secretHash, 0); + Token::at(asset).shield(&mut context, context.this_address(), refund, secret_hash, 0); } } diff --git a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr index 8b5d9dec486e..b50623ca1363 100644 --- a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr @@ -44,7 +44,7 @@ contract ImportTest { // Used for testing calling a function with no arguments // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(private)] - fn callNoArgs(target: AztecAddress) -> Field { + fn call_no_args(target: AztecAddress) -> Field { let test_contract_instance = TestPrivateContextInterface::at(target); let return_values = test_contract_instance.get_this_address(&mut context); @@ -55,7 +55,7 @@ contract ImportTest { // Used for testing calling an open function // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(private)] - fn callOpenFn(target: AztecAddress) { + fn call_open_fn(target: AztecAddress) { let test_contract_instance = TestPrivateContextInterface::at(target); test_contract_instance.create_nullifier_public(&mut context, 1, 2); } @@ -64,7 +64,7 @@ contract ImportTest { // Used for testing calling an open function from another open function // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(public)] - fn pubCallOpenFn(target: AztecAddress) -> Field { + fn pub_call_open_fn(target: AztecAddress) -> Field { let test_contract_instance = TestPublicContextInterface::at(target); let ret = test_contract_instance.create_nullifier_public(&mut context, 1, 2); diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index 721c3d149abb..63e568edacd4 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -303,8 +303,8 @@ contract Lending { storage.static_debt.at(owner).write(debt_returns.static_debt.to_integer()); } - unconstrained fn get_asset(assetId: Field) -> pub Asset { - storage.assets.at(assetId).read() + unconstrained fn get_asset(asset_id: Field) -> pub Asset { + storage.assets.at(asset_id).read() } unconstrained fn get_position(owner: AztecAddress) -> pub Position { diff --git a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr index 4c7f8ea594c9..d0d7c452f707 100644 --- a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr @@ -2,158 +2,158 @@ contract Parent { use dep::aztec::prelude::{AztecAddress, FunctionSelector}; - // Private function to call another private function in the targetContract using the provided selector + // Private function to call another private function in the target_contract using the provided selector #[aztec(private)] - fn entryPoint(targetContract: AztecAddress, targetSelector: FunctionSelector) -> Field { + fn entry_point(target_contract: AztecAddress, target_selector: FunctionSelector) -> Field { // Call the target private function - let return_values = context.call_private_function(targetContract, targetSelector, [0]); + let return_values = context.call_private_function(target_contract, target_selector, [0]); // Copy the return value from the call to this function's return values return_values[0] } - // Public function to directly call another public function to the targetContract using the selector and value provided + // Public function to directly call another public function to the target_contract using the selector and value provided #[aztec(public)] - fn pubEntryPoint( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - initValue: Field + fn pub_entry_point( + target_contract: AztecAddress, + target_selector: FunctionSelector, + init_value: Field ) -> Field { - let return_values = context.call_public_function(targetContract, targetSelector, [initValue]); + let return_values = context.call_public_function(target_contract, target_selector, [init_value]); return_values[0] } - // Same as pubEntryPoint, but calls the target contract twice, using the return value from the first invocation as the argument for the second. + // Same as pub_entry_point, but calls the target contract twice, using the return value from the first invocation as the argument for the second. #[aztec(public)] - fn pubEntryPointTwice( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - initValue: Field + fn pub_entry_point_twice( + target_contract: AztecAddress, + target_selector: FunctionSelector, + init_value: Field ) -> Field { - let returnValue = context.call_public_function(targetContract, targetSelector, [initValue])[0]; - let return_values = context.call_public_function(targetContract, targetSelector, [returnValue]); + let return_value = context.call_public_function(target_contract, target_selector, [init_value])[0]; + let return_values = context.call_public_function(target_contract, target_selector, [return_value]); return_values[0] } - // Private function to enqueue a call to the targetContract address using the selector and argument provided + // Private function to enqueue a call to the target_contract address using the selector and argument provided #[aztec(private)] - fn enqueueCallToChild( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - targetValue: Field + fn enqueue_call_to_child( + target_contract: AztecAddress, + target_selector: FunctionSelector, + target_value: Field ) { - context.call_public_function(targetContract, targetSelector, [targetValue]); + context.call_public_function(target_contract, target_selector, [target_value]); } // Private function that enqueues two calls to a child contract: - // - one through a nested call to enqueueCallToChild with value 10, + // - one through a nested call to enqueue_call_to_child with value 10, // - followed by one issued directly from this function with value 20. #[aztec(private)] - fn enqueueCallsToChildWithNestedFirst( - targetContract: AztecAddress, - targetSelector: FunctionSelector + fn enqueue_calls_to_child_with_nested_first( + target_contract: AztecAddress, + target_selector: FunctionSelector ) { - let enqueueCallToChildSelector = FunctionSelector::from_signature("enqueueCallToChild((Field),(u32),Field)"); + let enqueue_call_to_child_selector = FunctionSelector::from_signature("enqueue_call_to_child((Field),(u32),Field)"); let _ret = context.call_private_function( context.this_address(), - enqueueCallToChildSelector, - [targetContract.to_field(), targetSelector.to_field(), 10] + enqueue_call_to_child_selector, + [target_contract.to_field(), target_selector.to_field(), 10] ); - context.call_public_function(targetContract, targetSelector, [20]); + context.call_public_function(target_contract, target_selector, [20]); } // Private function that enqueues two calls to a child contract: // - one issued directly from this function with value 20, - // - followed by one through a nested call to enqueueCallToChild with value 10. + // - followed by one through a nested call to enqueue_call_to_child with value 10. #[aztec(private)] - fn enqueueCallsToChildWithNestedLast( - targetContract: AztecAddress, - targetSelector: FunctionSelector + fn enqueue_calls_to_child_with_nested_last( + target_contract: AztecAddress, + target_selector: FunctionSelector ) { - context.call_public_function(targetContract, targetSelector, [20]); - let enqueueCallToChildSelector = FunctionSelector::from_signature("enqueueCallToChild((Field),(u32),Field)"); + context.call_public_function(target_contract, target_selector, [20]); + let enqueue_call_to_child_selector = FunctionSelector::from_signature("enqueue_call_to_child((Field),(u32),Field)"); let _ret = context.call_private_function( context.this_address(), - enqueueCallToChildSelector, - [targetContract.to_field(), targetSelector.to_field(), 10] + enqueue_call_to_child_selector, + [target_contract.to_field(), target_selector.to_field(), 10] ); } - // Private function to enqueue a call to the targetContract address using the selector and argument provided + // Private function to enqueue a call to the target_contract address using the selector and argument provided #[aztec(private)] - fn enqueueCallToChildTwice( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - targetValue: Field + fn enqueue_call_to_child_twice( + target_contract: AztecAddress, + target_selector: FunctionSelector, + target_value: Field ) { // Enqueue the first public call - context.call_public_function(targetContract, targetSelector, [targetValue]); + context.call_public_function(target_contract, target_selector, [target_value]); // Enqueue the second public call - context.call_public_function(targetContract, targetSelector, [targetValue + 1]); + context.call_public_function(target_contract, target_selector, [target_value + 1]); } // Private function to enqueue a call to the pubEntryPoint function of this same contract, passing the target arguments provided #[aztec(private)] - fn enqueueCallToPubEntryPoint( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - targetValue: Field + fn enqueue_call_to_pub_entry_point( + target_contract: AztecAddress, + target_selector: FunctionSelector, + target_value: Field ) { - let pubEntryPointSelector = FunctionSelector::from_signature("pubEntryPoint((Field),(u32),Field)"); - let thisAddress = context.this_address(); + let pub_entry_point_selector = FunctionSelector::from_signature("pub_entry_point((Field),(u32),Field)"); + let this_address = context.this_address(); let _void = context.call_public_function( - thisAddress, - pubEntryPointSelector, - [targetContract.to_field(), targetSelector.to_field(), targetValue] + this_address, + pub_entry_point_selector, + [target_contract.to_field(), target_selector.to_field(), target_value] ); } - // Private function to enqueue two calls to the pubEntryPoint function of this same contract, passing the target arguments provided + // Private function to enqueue two calls to the pub_entry_point function of this same contract, passing the target arguments provided #[aztec(private)] - fn enqueueCallsToPubEntryPoint( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - targetValue: Field + fn enqueue_calls_to_pub_entry_point( + target_contract: AztecAddress, + target_selector: FunctionSelector, + target_value: Field ) { - let pubEntryPointSelector = FunctionSelector::from_signature("pubEntryPoint((Field),(u32),Field)"); - let thisAddress = context.this_address(); + let pub_entry_point_selector = FunctionSelector::from_signature("pub_entry_point((Field),(u32),Field)"); + let this_address = context.this_address(); context.call_public_function( - thisAddress, - pubEntryPointSelector, - [targetContract.to_field(), targetSelector.to_field(), targetValue] + this_address, + pub_entry_point_selector, + [target_contract.to_field(), target_selector.to_field(), target_value] ); context.call_public_function( - thisAddress, - pubEntryPointSelector, - [targetContract.to_field(), targetSelector.to_field(), targetValue + 1] + this_address, + pub_entry_point_selector, + [target_contract.to_field(), target_selector.to_field(), target_value + 1] ); } #[aztec(private)] - fn privateStaticCall( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn private_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 2] ) -> Field { // Call the target private function - let return_values = context.static_call_private_function(targetContract, targetSelector, args); + let return_values = context.static_call_private_function(target_contract, target_selector, args); // Copy the return value from the call to this function's return values return_values[0] } #[aztec(private)] - fn privateCall( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn private_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 2] ) -> Field { // Call the target private function - let return_values = context.call_private_function(targetContract, targetSelector, args); + let return_values = context.call_private_function(target_contract, target_selector, args); // Copy the return value from the call to this function's return values return_values[0] @@ -161,79 +161,79 @@ contract Parent { // Private function to set a static context and verify correct propagation for nested private calls #[aztec(private)] - fn privateStaticCallNested( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn private_nested_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 2] ) -> Field { // Call the target private function statically - let privateCallSelector = FunctionSelector::from_signature("privateCall((Field),(u32),[Field;2])"); - let thisAddress = context.this_address(); + let private_call_selector = FunctionSelector::from_signature("private_call((Field),(u32),[Field;2])"); + let this_address = context.this_address(); let return_values = context.static_call_private_function( - thisAddress, - privateCallSelector, - [targetContract.to_field(), targetSelector.to_field(), args[0], args[1]] + this_address, + private_call_selector, + [target_contract.to_field(), target_selector.to_field(), args[0], args[1]] ); // Copy the return value from the call to this function's return values return_values[0] } - // Public function to directly call another public function to the targetContract using the selector and value provided + // Public function to directly call another public function to the target_contract using the selector and value provided #[aztec(public)] - fn publicStaticCall( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn public_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) -> Field { - let return_values = context.static_call_public_function(targetContract, targetSelector, args); + let return_values = context.static_call_public_function(target_contract, target_selector, args); return_values[0] } // Public function to set a static context and verify correct propagation for nested public calls #[aztec(public)] - fn publicNestedStaticCall( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn public_nested_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) -> Field { // Call the target public function through the pub entrypoint statically - let pubEntryPointSelector = FunctionSelector::from_signature("pubEntryPoint((Field),(u32),Field)"); - let thisAddress = context.this_address(); + let pub_entry_point_selector = FunctionSelector::from_signature("pub_entry_point((Field),(u32),Field)"); + let this_address = context.this_address(); let return_values = context.static_call_public_function( - thisAddress, - pubEntryPointSelector, - [targetContract.to_field(), targetSelector.to_field(), args[0]] + this_address, + pub_entry_point_selector, + [target_contract.to_field(), target_selector.to_field(), args[0]] ); return_values[0] } - // Private function to enqueue a static call to the pubEntryPoint function of another contract, passing the target arguments provided + // Private function to enqueue a static call to the pub_entry_point function of another contract, passing the target arguments provided #[aztec(private)] - fn enqueueStaticNestedCallToPubFunction( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn enqueue_static_nested_call_to_pub_function( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) { // Call the target public function through the pub entrypoint statically - let pubEntryPointSelector = FunctionSelector::from_signature("pubEntryPoint((Field),(u32),Field)"); - let thisAddress = context.this_address(); + let pub_entry_point_selector = FunctionSelector::from_signature("pub_entry_point((Field),(u32),Field)"); + let this_address = context.this_address(); context.static_call_public_function( - thisAddress, - pubEntryPointSelector, - [targetContract.to_field(), targetSelector.to_field(), args[0]] + this_address, + pub_entry_point_selector, + [target_contract.to_field(), target_selector.to_field(), args[0]] ); } - // Private function to enqueue a static call to the pubEntryPoint function of another contract, passing the target arguments provided + // Private function to enqueue a static call to the pub_entry_point function of another contract, passing the target arguments provided #[aztec(private)] - fn enqueueStaticCallToPubFunction( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn enqueue_static_call_to_pub_function( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) { // Call the target private function - context.static_call_public_function(targetContract, targetSelector, args); + context.static_call_public_function(target_contract, target_selector, args); } } diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr index c18c6628c859..31cfcb9fe705 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr @@ -21,7 +21,7 @@ contract PriceFeed { storage.assets.at(asset_id).read() } - unconstrained fn fetch_price(assetId: Field) -> pub Asset { - storage.assets.at(assetId).read() + unconstrained fn fetch_price(asset_id: Field) -> pub Asset { + storage.assets.at(asset_id).read() } } diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index f5139cf61dcc..f721d48fd90e 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -359,8 +359,8 @@ contract Test { } // Purely exists for testing - unconstrained fn get_random(kindaSeed: Field) -> pub Field { - kindaSeed * rand() + unconstrained fn get_random(kinda_seed: Field) -> pub Field { + kinda_seed * rand() } struct DummyNote { diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index 9611aa25d6fc..c02dbe0fd4df 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -52,11 +52,11 @@ contract TokenBridge { fn exit_to_l1_public( recipient: EthAddress, // ethereum address to withdraw to amount: Field, - callerOnL1: EthAddress, // ethereum address that can call this function on the L1 portal (0x0 if anyone can call) + caller_on_l1: EthAddress, // ethereum address that can call this function on the L1 portal (0x0 if anyone can call) nonce: Field // nonce used in the approval message by `msg.sender` to let bridge burn their tokens on L2 ) { // Send an L2 to L1 message - let content = get_withdraw_content_hash(recipient, amount, callerOnL1); + let content = get_withdraw_content_hash(recipient, amount, caller_on_l1); context.message_portal(context.this_portal_address(), content); // Burn tokens @@ -100,11 +100,11 @@ contract TokenBridge { token: AztecAddress, recipient: EthAddress, // ethereum address to withdraw to amount: Field, - callerOnL1: EthAddress, // ethereum address that can call this function on the L1 portal (0x0 if anyone can call) + caller_on_l1: EthAddress, // ethereum address that can call this function on the L1 portal (0x0 if anyone can call) nonce: Field // nonce used in the approval message by `msg.sender` to let bridge burn their tokens on L2 ) { // Send an L2 to L1 message - let content = get_withdraw_content_hash(recipient, amount, callerOnL1); + let content = get_withdraw_content_hash(recipient, amount, caller_on_l1); context.message_portal(context.this_portal_address(), content); // docs:start:call_assert_token_is_same diff --git a/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr b/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr index 399baa4001e9..cba27bb6ef90 100644 --- a/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr @@ -54,7 +54,7 @@ pub fn get_mint_private_content_hash( // docs:start:get_withdraw_content_hash // Computes a content hash of a withdraw message. -pub fn get_withdraw_content_hash(recipient: EthAddress, amount: Field, callerOnL1: EthAddress) -> Field { +pub fn get_withdraw_content_hash(recipient: EthAddress, amount: Field, caller_on_l1: EthAddress) -> Field { // Compute the content hash // Compute sha256(selector || amount || recipient) // then convert to a single field element @@ -62,7 +62,7 @@ pub fn get_withdraw_content_hash(recipient: EthAddress, amount: Field, callerOnL let mut hash_bytes: [u8; 100] = [0; 100]; let recipient_bytes = recipient.to_field().to_be_bytes(32); let amount_bytes = amount.to_be_bytes(32); - let callerOnL1_bytes = callerOnL1.to_field().to_be_bytes(32); + let caller_on_l1_bytes = caller_on_l1.to_field().to_be_bytes(32); // 0x69328dec, selector for "withdraw(address,uint256,address)" hash_bytes[0] = 0x69; @@ -73,7 +73,7 @@ pub fn get_withdraw_content_hash(recipient: EthAddress, amount: Field, callerOnL for i in 0..32 { hash_bytes[i + 4] = recipient_bytes[i]; hash_bytes[i + 36] = amount_bytes[i]; - hash_bytes[i + 68] = callerOnL1_bytes[i]; + hash_bytes[i + 68] = caller_on_l1_bytes[i]; } let content_hash = sha256_to_field(hash_bytes); content_hash diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr index 69972b4fb7aa..81bf1824bfb4 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr @@ -65,13 +65,13 @@ impl TokenBridge { context: &mut PublicContext, recipient: EthAddress, amount: Field, - callerOnL1: EthAddress, + caller_on_l1: EthAddress, nonce: Field ) { let _ = context.call_public_function( self.address, FunctionSelector::from_signature("exit_to_l1_public((Field),Field,(Field),Field)"), - [recipient.to_field(), amount, callerOnL1.to_field(), nonce] + [recipient.to_field(), amount, caller_on_l1.to_field(), nonce] ); } } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr index 686ee06734e5..c98f1a6d6ac2 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr @@ -4,7 +4,7 @@ use dep::types::{ mocked::AggregationObject, hash::accumulate_sha256, constants::{ NUM_FIELDS_PER_SHA256, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_UNENCRYPTED_LOGS_HASHES_PER_TX, NUM_ENCRYPTED_LOGS_HASHES_PER_TX, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_unencrypted_logs_hashES_PER_TX, NUM_ENCRYPTED_LOGS_HASHES_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }, utils::uint256::U256, @@ -149,10 +149,10 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM let revert_code = combined.revert_code; let new_note_hashes = combined.new_note_hashes; let new_nullifiers = combined.new_nullifiers; - let newL2ToL1msgs = combined.new_l2_to_l1_msgs; + let new_l2_to_l1_msgs = combined.new_l2_to_l1_msgs; let public_data_update_requests = combined.public_data_update_requests; - let encryptedLogsHash = combined.encrypted_logs_hash; - let unencryptedLogsHash = combined.unencrypted_logs_hash; + let encrypted_logs_hash = combined.encrypted_logs_hash; + let unencrypted_logs_hash = combined.unencrypted_logs_hash; let mut offset = 0; @@ -171,7 +171,7 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM offset += MAX_NEW_NULLIFIERS_PER_TX ; for j in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { - txs_effects_hash_input[offset + j] = newL2ToL1msgs[j]; + txs_effects_hash_input[offset + j] = new_l2_to_l1_msgs[j]; } offset += MAX_NEW_L2_TO_L1_MSGS_PER_TX; @@ -184,16 +184,16 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM offset += MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2; for j in 0..NUM_FIELDS_PER_SHA256 { - txs_effects_hash_input[offset + j] = encryptedLogsHash[j]; + txs_effects_hash_input[offset + j] = encrypted_logs_hash[j]; } offset += NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; for j in 0..NUM_FIELDS_PER_SHA256 { - txs_effects_hash_input[offset + j] = unencryptedLogsHash[j]; + txs_effects_hash_input[offset + j] = unencrypted_logs_hash[j]; } - offset += NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + offset += NUM_unencrypted_logs_hashES_PER_TX * NUM_FIELDS_PER_SHA256; assert_eq(offset, TX_EFFECTS_HASH_INPUT_FIELDS); // Sanity check let mut hash_input_flattened = [0; TX_EFFECTS_HASH_FULL_FIELDS * 32 + TX_EFFECTS_HASH_LOG_FIELDS * 16]; @@ -224,7 +224,7 @@ fn consistent_TX_EFFECTS_HASH_INPUT_FIELDS() { + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2 + MAX_NEW_L2_TO_L1_MSGS_PER_TX + NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256 - + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + + NUM_unencrypted_logs_hashES_PER_TX * NUM_FIELDS_PER_SHA256; assert(TX_EFFECTS_HASH_INPUT_FIELDS == expected_size, "tx effects hash input size is incorrect"); } @@ -232,7 +232,7 @@ fn consistent_TX_EFFECTS_HASH_INPUT_FIELDS() { fn consistent_tx_effects_hash_log_input_size() { assert_eq( TX_EFFECTS_HASH_LOG_FIELDS, NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256 - + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256, "tx effects hash log input field size is incorrect" + + NUM_unencrypted_logs_hashES_PER_TX * NUM_FIELDS_PER_SHA256, "tx effects hash log input field size is incorrect" ); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/append_only_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/append_only_tree.nr index b1faf2c06c73..b8ddea2a9843 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/append_only_tree.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/append_only_tree.nr @@ -5,28 +5,28 @@ use crate::{ pub fn insert_subtree_to_snapshot_tree( snapshot: AppendOnlyTreeSnapshot, - siblingPath: [Field; N], - emptySubtreeRoot: Field, - subtreeRootToInsert: Field, - subtreeDepth: u8 + sibling_path: [Field; N], + empty_subtree_root: Field, + subtree_root_to_insert: Field, + subtree_depth: u8 ) -> AppendOnlyTreeSnapshot { - // TODO(Lasse): Sanity check len of siblingPath > height of subtree + // TODO(Lasse): Sanity check len of sibling_path > height of subtree // TODO(Lasse): Ensure height of subtree is correct (eg 3 for commitments, 1 for contracts) - let leafIndexAtDepth = snapshot.next_available_leaf_index >> (subtreeDepth as u32); + let leaf_index_at_depth = snapshot.next_available_leaf_index >> (subtree_depth as u32); // Check that the current root is correct and that there is an empty subtree at the insertion location assert_check_membership( - emptySubtreeRoot, - leafIndexAtDepth as Field, - siblingPath, + empty_subtree_root, + leaf_index_at_depth as Field, + sibling_path, snapshot.root ); - // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtreeDepth` levels up. - let new_root = root_from_sibling_path(subtreeRootToInsert, leafIndexAtDepth as Field, siblingPath); + // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtree_depth` levels up. + let new_root = root_from_sibling_path(subtree_root_to_insert, leaf_index_at_depth as Field, sibling_path); - // 2^subtreeDepth is the number of leaves added. 2^x = 1 << x - let new_next_available_leaf_index = (snapshot.next_available_leaf_index as u64) + (1 << (subtreeDepth as u64)); + // 2^subtree_depth is the number of leaves added. 2^x = 1 << x + let new_next_available_leaf_index = (snapshot.next_available_leaf_index as u64) + (1 << (subtree_depth as u64)); AppendOnlyTreeSnapshot { root: new_root, next_available_leaf_index: new_next_available_leaf_index as u32 } } diff --git a/yarn-project/aztec.js/README.md b/yarn-project/aztec.js/README.md index 46f84df88f8b..294667159a81 100644 --- a/yarn-project/aztec.js/README.md +++ b/yarn-project/aztec.js/README.md @@ -37,6 +37,6 @@ console.log(`Transferred ${amount} to ${recipientAddress} on block ${tx.blockNum import { Contract } from '@aztec/aztec.js'; const contract = await Contract.at(contractAddress, MyContractArtifact, wallet); -const balance = await contract.methods.getBalance(wallet.getAddress()).view(); +const balance = await contract.methods.get_balance(wallet.getAddress()).view(); console.log(`Account balance is ${balance}`); ``` diff --git a/yarn-project/end-to-end/src/docs_examples.test.ts b/yarn-project/end-to-end/src/docs_examples.test.ts index 93eab76cfcb6..c09c088bd40f 100644 --- a/yarn-project/end-to-end/src/docs_examples.test.ts +++ b/yarn-project/end-to-end/src/docs_examples.test.ts @@ -42,5 +42,5 @@ const _tx = await contract.methods.transfer(1, wallet).send().wait(); // docs:end:send_transaction // docs:start:call_view_function -const _balance = await contract.methods.getBalance(wallet.getAddress()).view(); +const _balance = await contract.methods.get_balance(wallet.getAddress()).view(); // docs:end:call_view_function diff --git a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts index 06e3a3f4f44a..80f970483b16 100644 --- a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts +++ b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts @@ -194,7 +194,7 @@ describe('e2e_2_pxes', () => { const newValueToSet = new Fr(256n); const childContractWithWalletB = await ChildContract.at(childCompleteAddress.address, walletB); - await childContractWithWalletB.methods.pubIncValue(newValueToSet).send().wait({ interval: 0.1 }); + await childContractWithWalletB.methods.pub_inc_value(newValueToSet).send().wait({ interval: 0.1 }); await awaitServerSynchronized(pxeA); diff --git a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts index 90807e53ee94..beb19f2ef511 100644 --- a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts +++ b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts @@ -51,7 +51,7 @@ function itShouldBehaveLikeAnAccountContract( it('calls a public function', async () => { const { logger, pxe } = context; logger('Calling public function...'); - await child.methods.pubIncValue(42).send().wait({ interval: 0.1 }); + await child.methods.pub_inc_value(42).send().wait({ interval: 0.1 }); const storedValue = await pxe.getPublicStorageAt(child.address, new Fr(1)); expect(storedValue).toEqual(new Fr(42n)); }, 60_000); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts index 9a520f6a2100..16b7f039402a 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts @@ -31,7 +31,7 @@ describe('e2e_nested_contract', () => { it('performs nested calls', async () => { await parentContract.methods - .entryPoint(childContract.address, childContract.methods.value.selector) + .entry_point(childContract.address, childContract.methods.value.selector) .send() .wait(); @@ -68,21 +68,21 @@ describe('e2e_nested_contract', () => { it('fails simulation if calling a function not allowed to be called externally', async () => { await expect( parentContract.methods - .entryPoint(childContract.address, (childContract.methods as any).valueInternal.selector) + .entry_point(childContract.address, (childContract.methods as any).value_internal.selector) .simulate(), - ).rejects.toThrow(/Assertion failed: Function valueInternal can only be called internally/); + ).rejects.toThrow(/Assertion failed: Function value_internal can only be called internally/); }, 100_000); it('performs public nested calls', async () => { await parentContract.methods - .pubEntryPoint(childContract.address, childContract.methods.pubGetValue.selector, 42n) + .pub_entry_point(childContract.address, childContract.methods.pub_get_value.selector, 42n) .send() .wait(); }, 100_000); it('enqueues a single public call', async () => { await parentContract.methods - .enqueueCallToChild(childContract.address, childContract.methods.pubIncValue.selector, 42n) + .enqueue_call_to_child(childContract.address, childContract.methods.pub_inc_value.selector, 42n) .send() .wait(); expect(await getChildStoredValue(childContract)).toEqual(new Fr(42n)); @@ -91,14 +91,14 @@ describe('e2e_nested_contract', () => { it('fails simulation if calling a public function not allowed to be called externally', async () => { await expect( parentContract.methods - .enqueueCallToChild(childContract.address, (childContract.methods as any).pubIncValueInternal.selector, 42n) + .enqueue_call_to_child(childContract.address, (childContract.methods as any).pub_inc_value_internal.selector, 42n) .simulate(), - ).rejects.toThrow(/Assertion failed: Function pubIncValueInternal can only be called internally/); + ).rejects.toThrow(/Assertion failed: Function pub_inc_value_internal can only be called internally/); }, 100_000); it('enqueues multiple public calls', async () => { await parentContract.methods - .enqueueCallToChildTwice(childContract.address, childContract.methods.pubIncValue.selector, 42n) + .enqueue_call_to_child_twice(childContract.address, childContract.methods.pub_inc_value.selector, 42n) .send() .wait(); expect(await getChildStoredValue(childContract)).toEqual(new Fr(85n)); @@ -106,7 +106,7 @@ describe('e2e_nested_contract', () => { it('enqueues a public call with nested public calls', async () => { await parentContract.methods - .enqueueCallToPubEntryPoint(childContract.address, childContract.methods.pubIncValue.selector, 42n) + .enqueue_call_to_pub_entry_point(childContract.address, childContract.methods.pub_inc_value.selector, 42n) .send() .wait(); expect(await getChildStoredValue(childContract)).toEqual(new Fr(42n)); @@ -114,7 +114,7 @@ describe('e2e_nested_contract', () => { it('enqueues multiple public calls with nested public calls', async () => { await parentContract.methods - .enqueueCallsToPubEntryPoint(childContract.address, childContract.methods.pubIncValue.selector, 42n) + .enqueue_calls_to_pub_entry_point(childContract.address, childContract.methods.pub_inc_value.selector, 42n) .send() .wait(); expect(await getChildStoredValue(childContract)).toEqual(new Fr(85n)); @@ -123,7 +123,7 @@ describe('e2e_nested_contract', () => { // Regression for https://github.com/AztecProtocol/aztec-packages/issues/640 it('reads fresh value after write within the same tx', async () => { await parentContract.methods - .pubEntryPointTwice(childContract.address, childContract.methods.pubIncValue.selector, 42n) + .pub_entry_point_twice(childContract.address, childContract.methods.pub_inc_value.selector, 42n) .send() .wait(); expect(await getChildStoredValue(childContract)).toEqual(new Fr(84n)); @@ -134,10 +134,10 @@ describe('e2e_nested_contract', () => { // through the account contract, if the account entrypoint behaves properly, it will honor // this order and not run the private call first which results in the public calls being inverted. it('executes public calls in expected order', async () => { - const pubSetValueSelector = childContract.methods.pubSetValue.selector; + const pub_set_valueSelector = childContract.methods.pub_set_value.selector; const actions = [ - childContract.methods.pubSetValue(20n).request(), - parentContract.methods.enqueueCallToChild(childContract.address, pubSetValueSelector, 40n).request(), + childContract.methods.pub_set_value(20n).request(), + parentContract.methods.enqueue_call_to_child(childContract.address, pub_set_valueSelector, 40n).request(), ]; const tx = await new BatchCall(wallet, actions).send().wait(); @@ -170,17 +170,17 @@ describe('e2e_nested_contract', () => { it('calls a method no arguments', async () => { logger(`Calling noargs on importer contract`); - await importerContract.methods.callNoArgs(testContract.address).send().wait(); + await importerContract.methods.call_no_args(testContract.address).send().wait(); }, 30_000); it('calls an open function', async () => { logger(`Calling openfn on importer contract`); - await importerContract.methods.callOpenFn(testContract.address).send().wait(); + await importerContract.methods.call_open_fn(testContract.address).send().wait(); }, 30_000); it('calls an open function from an open function', async () => { logger(`Calling pub openfn on importer contract`); - await importerContract.methods.pubCallOpenFn(testContract.address).send().wait(); + await importerContract.methods.pub_call_open_fn(testContract.address).send().wait(); }, 30_000); }); }); diff --git a/yarn-project/end-to-end/src/e2e_ordering.test.ts b/yarn-project/end-to-end/src/e2e_ordering.test.ts index 68836b1b2e3f..61ea0eae83e4 100644 --- a/yarn-project/end-to-end/src/e2e_ordering.test.ts +++ b/yarn-project/end-to-end/src/e2e_ordering.test.ts @@ -41,7 +41,7 @@ describe('e2e_ordering', () => { beforeEach(async () => { parent = await ParentContract.deploy(wallet).send().deployed(); child = await ChildContract.deploy(wallet).send().deployed(); - pubSetValueSelector = child.methods.pubSetValue.selector; + pubSetValueSelector = child.methods.pub_set_value.selector; }); describe('enqueued public calls ordering', () => { @@ -49,11 +49,11 @@ describe('e2e_ordering', () => { const directValue = 20n; const expectedOrders = { - enqueueCallsToChildWithNestedFirst: [nestedValue, directValue] as bigint[], - enqueueCallsToChildWithNestedLast: [directValue, nestedValue] as bigint[], + enqueue_calls_to_child_with_nested_first: [nestedValue, directValue] as bigint[], + enqueue_calls_to_child_with_nested_last: [directValue, nestedValue] as bigint[], } as const; - it.each(['enqueueCallsToChildWithNestedFirst', 'enqueueCallsToChildWithNestedLast'] as const)( + it.each(['enqueue_calls_to_child_with_nested_first', 'enqueue_calls_to_child_with_nested_last'] as const)( 'orders public function execution in %s', async method => { const expectedOrder = expectedOrders[method]; @@ -91,11 +91,11 @@ describe('e2e_ordering', () => { const directValue = 20n; const expectedOrders = { - setValueTwiceWithNestedFirst: [nestedValue, directValue] as bigint[], - setValueTwiceWithNestedLast: [directValue, nestedValue] as bigint[], + set_value_twice_with_nested_first: [nestedValue, directValue] as bigint[], + set_value_twice_with_nested_last: [directValue, nestedValue] as bigint[], } as const; - it.each(['setValueTwiceWithNestedFirst', 'setValueTwiceWithNestedLast'] as const)( + it.each(['set_value_twice_with_nested_first', 'set_value_twice_with_nested_last'] as const)( 'orders public state updates in %s (and ensures final state value is correct)', async method => { const expectedOrder = expectedOrders[method]; @@ -112,9 +112,9 @@ describe('e2e_ordering', () => { // Emitting logs twice (first in a nested call, then directly) leads // to a misordering of them by the public kernel because it sees them // in reverse order. More info in this thread: https://discourse.aztec.network/t/identifying-the-ordering-of-state-access-across-contract-calls/382/12#transition-counters-for-private-calls-2 - // Once fixed, re-include the `setValueTwiceWithNestedFirst` test - //it.each(['setValueTwiceWithNestedFirst', 'setValueTwiceWithNestedLast'] as const)( - it.each(['setValueTwiceWithNestedLast'] as const)('orders unencrypted logs in %s', async method => { + // Once fixed, re-include the `set_value_twice_with_nested_first` test + //it.each(['set_value_twice_with_nested_first', 'set_value_twice_with_nested_last'] as const)( + it.each(['set_value_twice_with_nested_last'] as const)('orders unencrypted logs in %s', async method => { const expectedOrder = expectedOrders[method]; await child.methods[method]().send().wait(); diff --git a/yarn-project/end-to-end/src/e2e_static_calls.test.ts b/yarn-project/end-to-end/src/e2e_static_calls.test.ts index 974d3ce3f454..59b4a37ae8b6 100644 --- a/yarn-project/end-to-end/src/e2e_static_calls.test.ts +++ b/yarn-project/end-to-end/src/e2e_static_calls.test.ts @@ -23,7 +23,7 @@ describe('e2e_static_calls', () => { describe('parent calls child', () => { it('performs legal private to private static calls', async () => { await parentContract.methods - .privateStaticCall(childContract.address, childContract.methods.privateGetValue.selector, [ + .private_static_call(childContract.address, childContract.methods.private_get_value.selector, [ 42n, wallet.getCompleteAddress().address, ]) @@ -33,7 +33,7 @@ describe('e2e_static_calls', () => { it('performs legal (nested) private to private static calls', async () => { await parentContract.methods - .privateStaticCallNested(childContract.address, childContract.methods.privateGetValue.selector, [ + .private_nested_static_call(childContract.address, childContract.methods.private_get_value.selector, [ 42n, wallet.getCompleteAddress().address, ]) @@ -43,28 +43,28 @@ describe('e2e_static_calls', () => { it('performs legal public to public static calls', async () => { await parentContract.methods - .publicStaticCall(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .public_static_call(childContract.address, childContract.methods.pub_get_value.selector, [42n]) .send() .wait(); }, 100_000); it('performs legal (nested) public to public static calls', async () => { await parentContract.methods - .publicNestedStaticCall(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .public_nested_static_call(childContract.address, childContract.methods.pub_get_value.selector, [42n]) .send() .wait(); }, 100_000); it('performs legal enqueued public static calls', async () => { await parentContract.methods - .enqueueStaticCallToPubFunction(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.pub_get_value.selector, [42n]) .send() .wait(); }, 100_000); it('performs legal (nested) enqueued public static calls', async () => { await parentContract.methods - .enqueueStaticNestedCallToPubFunction(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .enqueue_static_nested_call_to_pub_function(childContract.address, childContract.methods.pub_get_value.selector, [42n]) .send() .wait(); }, 100_000); @@ -72,7 +72,7 @@ describe('e2e_static_calls', () => { it('fails when performing illegal private to private static calls', async () => { await expect( parentContract.methods - .privateStaticCall(childContract.address, childContract.methods.privateSetValue.selector, [ + .private_static_call(childContract.address, childContract.methods.private_set_value.selector, [ 42n, wallet.getCompleteAddress().address, ]) @@ -84,7 +84,7 @@ describe('e2e_static_calls', () => { it('fails when performing illegal (nested) private to private static calls', async () => { await expect( parentContract.methods - .privateStaticCallNested(childContract.address, childContract.methods.privateSetValue.selector, [ + .private_nested_static_call(childContract.address, childContract.methods.private_set_value.selector, [ 42n, wallet.getCompleteAddress().address, ]) @@ -96,7 +96,7 @@ describe('e2e_static_calls', () => { it('fails when performing illegal public to public static calls', async () => { await expect( parentContract.methods - .publicStaticCall(childContract.address, childContract.methods.pubSetValue.selector, [42n]) + .public_static_call(childContract.address, childContract.methods.pub_set_value.selector, [42n]) .send() .wait(), ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); @@ -105,7 +105,7 @@ describe('e2e_static_calls', () => { it('fails when performing illegal (nested) public to public static calls', async () => { await expect( parentContract.methods - .publicNestedStaticCall(childContract.address, childContract.methods.pubSetValue.selector, [42n]) + .public_nested_static_call(childContract.address, childContract.methods.pub_set_value.selector, [42n]) .send() .wait(), ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); @@ -114,7 +114,7 @@ describe('e2e_static_calls', () => { it('fails when performing illegal enqueued public static calls', async () => { await expect( parentContract.methods - .enqueueStaticCallToPubFunction(childContract.address, childContract.methods.pubSetValue.selector, [42n]) + .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.pub_set_value.selector, [42n]) .send() .wait(), ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); @@ -123,7 +123,7 @@ describe('e2e_static_calls', () => { it('fails when performing illegal (nested) enqueued public static calls', async () => { await expect( parentContract.methods - .enqueueStaticNestedCallToPubFunction(childContract.address, childContract.methods.pubSetValue.selector, [ + .enqueue_static_nested_call_to_pub_function(childContract.address, childContract.methods.pub_set_value.selector, [ 42n, ]) .send() diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 2abe169627f5..1e4e05227227 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -438,7 +438,7 @@ describe('Private Execution test suite', () => { it('parent should call child', async () => { const childArtifact = getFunctionArtifact(ChildContractArtifact, 'value'); - const parentArtifact = getFunctionArtifact(ParentContractArtifact, 'entryPoint'); + const parentArtifact = getFunctionArtifact(ParentContractArtifact, 'entry_point'); const parentAddress = AztecAddress.random(); const childAddress = AztecAddress.random(); const childSelector = FunctionSelector.fromNameAndParameters(childArtifact.name, childArtifact.parameters); @@ -770,8 +770,8 @@ describe('Private Execution test suite', () => { describe('enqueued calls', () => { it.each([false, true])('parent should enqueue call to child (internal %p)', async isInternal => { - const parentArtifact = getFunctionArtifact(ParentContractArtifact, 'enqueueCallToChild'); - const childContractArtifact = ChildContractArtifact.functions.find(fn => fn.name === 'pubSetValue')!; + const parentArtifact = getFunctionArtifact(ParentContractArtifact, 'enqueue_call_to_child'); + const childContractArtifact = ChildContractArtifact.functions.find(fn => fn.name === 'pub_set_value')!; expect(childContractArtifact).toBeDefined(); const childAddress = AztecAddress.random(); const childPortalContractAddress = EthAddress.random(); diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index 01a2cbe946a3..c60e6d89502a 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -254,7 +254,7 @@ describe('ACIR public execution simulator', () => { ); const childContractAddress = AztecAddress.random(); - const childValueFn = ChildContractArtifact.functions.find(f => f.name === 'pubGetValue')!; + const childValueFn = ChildContractArtifact.functions.find(f => f.name === 'pub_get_value')!; const childValueFnSelector = FunctionSelector.fromNameAndParameters(childValueFn.name, childValueFn.parameters); const initialValue = 3n; From 7e903e4f22adce7b5b7e633c018149284fd72a15 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Thu, 21 Mar 2024 22:50:05 +0000 Subject: [PATCH 02/13] fix rest --- .../aztec-nr/aztec/src/context/avm_context.nr | 8 ++++---- noir-projects/aztec-nr/aztec/src/note/lifecycle.nr | 4 ++-- noir-projects/aztec-nr/aztec/src/note/utils.nr | 2 +- noir-projects/aztec-nr/aztec/src/oracle/notes.nr | 2 +- .../contracts/avm_test_contract/src/main.nr | 10 +++++----- .../contracts/import_test_contract/src/main.nr | 8 ++++---- .../contracts/parent_contract/src/main.nr | 2 +- .../crates/types/src/abis/combined_constant_data.nr | 2 +- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/context/avm_context.nr b/noir-projects/aztec-nr/aztec/src/context/avm_context.nr index 998d96e5996a..4f72dad449b4 100644 --- a/noir-projects/aztec-nr/aztec/src/context/avm_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/avm_context.nr @@ -121,7 +121,7 @@ impl PublicContextInterface for AVMContext { temporary_function_selector: FunctionSelector, args: [Field; ARGS_COUNT] ) -> [Field; RETURN_VALUES_LENGTH] { - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + let gas = [/*l1_gas*/42, /*l2_gas*/24, /*da_gas*/420]; let results = call( gas, @@ -142,7 +142,7 @@ impl PublicContextInterface for AVMContext { temporary_function_selector: FunctionSelector, args: [Field; ARGS_COUNT] ) -> [Field; RETURN_VALUES_LENGTH] { - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + let gas = [/*l1_gas*/42, /*l2_gas*/24, /*da_gas*/420]; let (data_to_return, success): ([Field; RETURN_VALUES_LENGTH], u8) = call_static( gas, @@ -263,7 +263,7 @@ fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) {} #[oracle(avmOpcodeCall)] fn call( - gas: [Field; 3], // gas allocation: [l1Gas, l2Gas, daGas] + gas: [Field; 3], // gas allocation: [l1_gas, l2_gas, da_gas] address: AztecAddress, args: [Field; ARGS_COUNT], // TODO(5110): consider passing in calldata directly @@ -273,7 +273,7 @@ fn call( #[oracle(avmOpcodeStaticCall)] fn call_static( - gas: [Field; 3], // gas allocation: [l1Gas, l2Gas, daGas] + gas: [Field; 3], // gas allocation: [l1_gas, l2_gas, da_gas] address: AztecAddress, args: [Field; ARGS_COUNT], // TODO(5110): consider passing in calldata directly diff --git a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr index dfad659a7170..2991d385290c 100644 --- a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr +++ b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr @@ -14,7 +14,7 @@ pub fn create_note( let contract_address = (*context).this_address(); let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true }; - // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + // TODO: change this to note.set_header(header) once https://github.com/noir-lang/noir/issues/4095 is fixed Note::set_header(note, header); // As `is_transient` is true, this will compute the inner note hsah let inner_note_hash = compute_note_hash_for_insertion(*note); @@ -46,7 +46,7 @@ pub fn create_note_hash_from_public( let contract_address = (*context).this_address(); let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true }; - // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + // TODO: change this to note.set_header(header) once https://github.com/noir-lang/noir/issues/4095 is fixed Note::set_header(note, header); let inner_note_hash = compute_note_hash_for_insertion(*note); diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index 6dd172ffff15..8732ca6be61f 100644 --- a/noir-projects/aztec-nr/aztec/src/note/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/note/utils.nr @@ -92,7 +92,7 @@ pub fn compute_note_hash_and_nullifier( serialized_note: [Field; S] // docs:end:compute_note_hash_and_nullifier_args ) -> [Field; 4] where T: NoteInterface { let mut note = deserialize_content(arr_copy_slice(serialized_note, [0; N], 0)); - // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + // TODO: change this to note.set_header(header) once https://github.com/noir-lang/noir/issues/4095 is fixed T::set_header((&mut note), note_header); let inner_note_hash = compute_inner_note_hash(note); diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index 50ee2367f0af..d4c5d75eec6e 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -133,7 +133,7 @@ unconstrained pub fn get_notes( let header = NoteHeader { contract_address, nonce, storage_slot, is_transient }; let serialized_note = arr_copy_slice(fields, [0; N], read_offset + 2); let mut note = Note::deserialize_content(serialized_note); - // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + // TODO: change this to note.set_header(header) once https://github.com/noir-lang/noir/issues/4095 is fixed Note::set_header(&mut note, header); placeholder_opt_notes[i] = Option::some(note); }; diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index f649857662b1..43a150ae1f8b 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -293,12 +293,12 @@ contract AvmTest { #[aztec(public-vm)] fn raw_nested_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field(); - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + let gas = [/*l1_gas*/42, /*l2_gas*/24, /*da_gas*/420]; // Nested call let results = context.call_public_function_raw(gas, context.this_address(), selector, [arg_a, arg_b]); let data_to_return: [Field; 1] = results.0; - // this explicit size ^ is necessary to ensure that retSize is compile-time + // this explicit size ^ is necessary to ensure that ret_size is compile-time // (ensure the data_to_return is in a HeapArray not a HeapVector) let success: u8 = results.1; @@ -315,7 +315,7 @@ contract AvmTest { // Nested call using standard context interface function let data_to_return: [Field; RETURN_VALUES_LENGTH] = context.call_public_function(context.this_address(), selector, [arg_a, arg_b]); - // this explicit size ^ is necessary to ensure that retSize is compile-time + // this explicit size ^ is necessary to ensure that ret_size is compile-time // (ensure the data_to_return is in a HeapArray not a HeapVector) let add_result = data_to_return[0]; @@ -326,7 +326,7 @@ contract AvmTest { #[aztec(public-vm)] fn raw_nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub (Field, u8) { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field(); - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + let gas = [/*l1_gas*/42, /*l2_gas*/24, /*da_gas*/420]; let (result_data, success): ([Field; 1], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, [arg_a, arg_b]); @@ -337,7 +337,7 @@ contract AvmTest { #[aztec(public-vm)] fn raw_nested_static_call_to_set_storage() -> pub u8 { let selector = FunctionSelector::from_signature("set_storage_single(Field)").to_field(); - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + let gas = [/*l1_gas*/42, /*l2_gas*/24, /*da_gas*/420]; let calldata: [Field; 1] = [20]; let (_data_to_return, success): ([Field; 0], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, calldata); diff --git a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr index b50623ca1363..d7bccb323759 100644 --- a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr @@ -11,7 +11,7 @@ contract ImportTest { ManyNotesADeepStructTestCodeGenStruct }; - // Calls the testCodeGen on the Test contract at the target address + // Calls the test_code_gen on the Test contract at the target address // Used for testing calling a function with arguments of multiple types // See yarn-project/simulator/src/client/private_execution.ts // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts @@ -40,7 +40,7 @@ contract ImportTest { return_values[0] } - // Calls the getThisAddress on the Test contract at the target address + // Calls the get_this_address on the Test contract at the target address // Used for testing calling a function with no arguments // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(private)] @@ -51,7 +51,7 @@ contract ImportTest { return_values[0] } - // Calls the createNullifierPublic on the Test contract at the target address + // Calls the create_nullifier_public on the Test contract at the target address // Used for testing calling an open function // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(private)] @@ -60,7 +60,7 @@ contract ImportTest { test_contract_instance.create_nullifier_public(&mut context, 1, 2); } - // Calls the createNullifierPublic on the Test contract at the target address + // Calls the create_nullifier_public on the Test contract at the target address // Used for testing calling an open function from another open function // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr index d0d7c452f707..472159dfe2c5 100644 --- a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr @@ -94,7 +94,7 @@ contract Parent { context.call_public_function(target_contract, target_selector, [target_value + 1]); } - // Private function to enqueue a call to the pubEntryPoint function of this same contract, passing the target arguments provided + // Private function to enqueue a call to the pub_entry_point function of this same contract, passing the target arguments provided #[aztec(private)] fn enqueue_call_to_pub_entry_point( target_contract: AztecAddress, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr index 1ae4ba6ce50e..9dc4974700f1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr @@ -3,7 +3,7 @@ use crate::header::Header; struct CombinedConstantData { historical_header: Header, - // Note: `chainId` and `version` in txContext are not redundant to the values in + // Note: `chain_id` and `version` in tx_context are not redundant to the values in // self.historical_header.global_variables because they can be different in case of a protocol upgrade. In such // a situation we could be using header from a block before the upgrade took place but be using the updated // protocol to execute and prove the transaction. From 6d0e0a82ede42d7191dc9524b113cc73e7136ec0 Mon Sep 17 00:00:00 2001 From: Esau Date: Fri, 22 Mar 2024 12:21:03 +0100 Subject: [PATCH 03/13] fix --- .../crates/rollup-lib/src/components.nr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr index ec24d830cb96..40b953328116 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr @@ -4,7 +4,7 @@ use dep::types::{ mocked::AggregationObject, hash::accumulate_sha256, constants::{ NUM_FIELDS_PER_SHA256, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_unencrypted_logs_hashES_PER_TX, NUM_ENCRYPTED_LOGS_HASHES_PER_TX, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_UNENCRYPTED_LOGS_HASHES_PER_TX, NUM_ENCRYPTED_LOGS_HASHES_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }, utils::uint256::U256, @@ -189,7 +189,7 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM txs_effects_hash_input[offset + j] = unencrypted_logs_hash[j]; } - offset += NUM_unencrypted_logs_hashES_PER_TX * NUM_FIELDS_PER_SHA256; + offset += NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; assert_eq(offset, TX_EFFECTS_HASH_INPUT_FIELDS); // Sanity check let mut hash_input_flattened = [0; TX_EFFECTS_HASH_INPUT_FIELDS * 32]; @@ -213,6 +213,6 @@ fn consistent_TX_EFFECTS_HASH_INPUT_FIELDS() { + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2 + MAX_NEW_L2_TO_L1_MSGS_PER_TX + NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256 - + NUM_unencrypted_logs_hashES_PER_TX * NUM_FIELDS_PER_SHA256; + + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; assert(TX_EFFECTS_HASH_INPUT_FIELDS == expected_size, "tx effects hash input size is incorrect"); } From dcf41e21cc4511b35accaf92214298a753fccd6d Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 22 Mar 2024 12:15:59 +0000 Subject: [PATCH 04/13] fix --- .../end-to-end/src/e2e_nested_contract.test.ts | 10 +++++++--- .../end-to-end/src/e2e_static_calls.test.ts | 18 +++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts index 16b7f039402a..8582ae4ecdee 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts @@ -91,7 +91,11 @@ describe('e2e_nested_contract', () => { it('fails simulation if calling a public function not allowed to be called externally', async () => { await expect( parentContract.methods - .enqueue_call_to_child(childContract.address, (childContract.methods as any).pub_inc_value_internal.selector, 42n) + .enqueue_call_to_child( + childContract.address, + (childContract.methods as any).pub_inc_value_internal.selector, + 42n, + ) .simulate(), ).rejects.toThrow(/Assertion failed: Function pub_inc_value_internal can only be called internally/); }, 100_000); @@ -134,10 +138,10 @@ describe('e2e_nested_contract', () => { // through the account contract, if the account entrypoint behaves properly, it will honor // this order and not run the private call first which results in the public calls being inverted. it('executes public calls in expected order', async () => { - const pub_set_valueSelector = childContract.methods.pub_set_value.selector; + const pubSetValueSelector = childContract.methods.pub_set_value.selector; const actions = [ childContract.methods.pub_set_value(20n).request(), - parentContract.methods.enqueue_call_to_child(childContract.address, pub_set_valueSelector, 40n).request(), + parentContract.methods.enqueue_call_to_child(childContract.address, pubSetValueSelector, 40n).request(), ]; const tx = await new BatchCall(wallet, actions).send().wait(); diff --git a/yarn-project/end-to-end/src/e2e_static_calls.test.ts b/yarn-project/end-to-end/src/e2e_static_calls.test.ts index 59b4a37ae8b6..1f09b63c629d 100644 --- a/yarn-project/end-to-end/src/e2e_static_calls.test.ts +++ b/yarn-project/end-to-end/src/e2e_static_calls.test.ts @@ -64,7 +64,11 @@ describe('e2e_static_calls', () => { it('performs legal (nested) enqueued public static calls', async () => { await parentContract.methods - .enqueue_static_nested_call_to_pub_function(childContract.address, childContract.methods.pub_get_value.selector, [42n]) + .enqueue_static_nested_call_to_pub_function( + childContract.address, + childContract.methods.pub_get_value.selector, + [42n], + ) .send() .wait(); }, 100_000); @@ -114,7 +118,9 @@ describe('e2e_static_calls', () => { it('fails when performing illegal enqueued public static calls', async () => { await expect( parentContract.methods - .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.pub_set_value.selector, [42n]) + .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.pub_set_value.selector, [ + 42n, + ]) .send() .wait(), ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); @@ -123,9 +129,11 @@ describe('e2e_static_calls', () => { it('fails when performing illegal (nested) enqueued public static calls', async () => { await expect( parentContract.methods - .enqueue_static_nested_call_to_pub_function(childContract.address, childContract.methods.pub_set_value.selector, [ - 42n, - ]) + .enqueue_static_nested_call_to_pub_function( + childContract.address, + childContract.methods.pub_set_value.selector, + [42n], + ) .send() .wait(), ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); From 72321039a32b13219f5450c26e1b1dcb1f1d7398 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 22 Mar 2024 12:55:13 +0000 Subject: [PATCH 05/13] fix --- yarn-project/end-to-end/src/e2e_ordering.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_ordering.test.ts b/yarn-project/end-to-end/src/e2e_ordering.test.ts index 61ea0eae83e4..5d5f205af566 100644 --- a/yarn-project/end-to-end/src/e2e_ordering.test.ts +++ b/yarn-project/end-to-end/src/e2e_ordering.test.ts @@ -49,8 +49,8 @@ describe('e2e_ordering', () => { const directValue = 20n; const expectedOrders = { - enqueue_calls_to_child_with_nested_first: [nestedValue, directValue] as bigint[], - enqueue_calls_to_child_with_nested_last: [directValue, nestedValue] as bigint[], + "enqueue_calls_to_child_with_nested_first": [nestedValue, directValue] as bigint[], + "enqueue_calls_to_child_with_nested_last": [directValue, nestedValue] as bigint[], } as const; it.each(['enqueue_calls_to_child_with_nested_first', 'enqueue_calls_to_child_with_nested_last'] as const)( @@ -91,8 +91,8 @@ describe('e2e_ordering', () => { const directValue = 20n; const expectedOrders = { - set_value_twice_with_nested_first: [nestedValue, directValue] as bigint[], - set_value_twice_with_nested_last: [directValue, nestedValue] as bigint[], + "set_value_twice_with_nested_first": [nestedValue, directValue] as bigint[], + "set_value_twice_with_nested_last": [directValue, nestedValue] as bigint[], } as const; it.each(['set_value_twice_with_nested_first', 'set_value_twice_with_nested_last'] as const)( From 294ca44670bd32db2f60529f79ea1d801e14cedd Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 22 Mar 2024 13:25:04 +0000 Subject: [PATCH 06/13] fix --- yarn-project/end-to-end/src/e2e_ordering.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_ordering.test.ts b/yarn-project/end-to-end/src/e2e_ordering.test.ts index 5d5f205af566..fbbdcc095d66 100644 --- a/yarn-project/end-to-end/src/e2e_ordering.test.ts +++ b/yarn-project/end-to-end/src/e2e_ordering.test.ts @@ -49,8 +49,8 @@ describe('e2e_ordering', () => { const directValue = 20n; const expectedOrders = { - "enqueue_calls_to_child_with_nested_first": [nestedValue, directValue] as bigint[], - "enqueue_calls_to_child_with_nested_last": [directValue, nestedValue] as bigint[], + enqueue_calls_to_child_with_nested_first: [nestedValue, directValue] as bigint[], // eslint-disable-line camelcase + enqueue_calls_to_child_with_nested_last: [directValue, nestedValue] as bigint[], // eslint-disable-line camelcase } as const; it.each(['enqueue_calls_to_child_with_nested_first', 'enqueue_calls_to_child_with_nested_last'] as const)( @@ -91,8 +91,8 @@ describe('e2e_ordering', () => { const directValue = 20n; const expectedOrders = { - "set_value_twice_with_nested_first": [nestedValue, directValue] as bigint[], - "set_value_twice_with_nested_last": [directValue, nestedValue] as bigint[], + set_value_twice_with_nested_first: [nestedValue, directValue] as bigint[], + set_value_twice_with_nested_last: [directValue, nestedValue] as bigint[], } as const; it.each(['set_value_twice_with_nested_first', 'set_value_twice_with_nested_last'] as const)( From aff9753d681f4403b05388894cc5d6d7ef2f58fa Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 22 Mar 2024 13:46:48 +0000 Subject: [PATCH 07/13] test --- yarn-project/end-to-end/src/e2e_ordering.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_ordering.test.ts b/yarn-project/end-to-end/src/e2e_ordering.test.ts index fbbdcc095d66..450bc0eb214a 100644 --- a/yarn-project/end-to-end/src/e2e_ordering.test.ts +++ b/yarn-project/end-to-end/src/e2e_ordering.test.ts @@ -91,8 +91,8 @@ describe('e2e_ordering', () => { const directValue = 20n; const expectedOrders = { - set_value_twice_with_nested_first: [nestedValue, directValue] as bigint[], - set_value_twice_with_nested_last: [directValue, nestedValue] as bigint[], + set_value_twice_with_nested_first: [nestedValue, directValue] as bigint[], // eslint-disable-line camelcase + set_value_twice_with_nested_last: [directValue, nestedValue] as bigint[], // eslint-disable-line camelcase } as const; it.each(['set_value_twice_with_nested_first', 'set_value_twice_with_nested_last'] as const)( From 5a0a5bd932fc3885f02caa02acfa91c9f10f046e Mon Sep 17 00:00:00 2001 From: MirandaWood Date: Fri, 22 Mar 2024 13:50:37 +0000 Subject: [PATCH 08/13] feat: remove NUM_FIELDS_PER_SHA256, single sha arrs --- l1-contracts/slither_output.md | 8 +-- .../src/core/libraries/ConstantsGen.sol | 1 - .../aztec/src/context/private_context.nr | 9 ++- .../aztec/src/context/public_context.nr | 11 ++-- .../aztec-nr/aztec/src/oracle/logs.nr | 10 ++-- .../src/utils/sha256_merkle_tree.nr | 4 +- .../src/private_kernel_init.nr | 8 +-- .../src/private_kernel_inner.nr | 8 +-- .../crates/public-kernel-lib/src/common.nr | 8 +-- .../src/public_kernel_app_logic.nr | 6 +- .../src/public_kernel_setup.nr | 6 +- .../src/public_kernel_teardown.nr | 6 +- .../base_or_merge_rollup_public_inputs.nr | 6 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 23 +++----- .../crates/rollup-lib/src/components.nr | 40 ++++++------- .../crates/rollup-lib/src/root.nr | 6 +- .../rollup-lib/src/root/root_rollup_inputs.nr | 2 +- .../src/tests/previous_rollup_data.nr | 8 +-- .../accumulated_revertible_data_builder.nr | 8 +-- .../combined_accumulated_data.nr | 8 +-- .../combined_accumulated_data_builder.nr | 8 +-- .../private_accumulated_revertible_data.nr | 8 +-- .../public_accumulated_revertible_data.nr | 8 +-- .../src/abis/private_circuit_public_inputs.nr | 15 +++-- .../src/abis/public_circuit_public_inputs.nr | 10 ++-- .../crates/types/src/constants.nr | 2 - .../crates/types/src/content_commitment.nr | 31 +++++----- .../crates/types/src/hash.nr | 17 +++--- .../types/src/tests/kernel_data_builder.nr | 6 +- .../src/tests/private_call_data_builder.nr | 6 +- .../private_circuit_public_inputs_builder.nr | 8 +-- .../src/tests/public_call_data_builder.nr | 4 +- .../public_circuit_public_inputs_builder.nr | 5 +- .../circuit-types/src/mocks_to_purge.ts | 5 +- .../circuit-types/src/tx/processed_tx.ts | 2 +- yarn-project/circuits.js/src/constants.gen.ts | 1 - .../__snapshots__/contract_class.test.ts.snap | 10 ++-- .../kernel/combined_accumulated_data.ts | 57 +++++++++---------- .../structs/private_circuit_public_inputs.ts | 25 ++++---- .../structs/public_circuit_public_inputs.ts | 13 ++--- .../base_or_merge_rollup_public_inputs.ts | 20 +++---- .../circuits.js/src/tests/factories.ts | 23 ++++---- .../src/integration_l1_publisher.test.ts | 5 +- .../src/__snapshots__/index.test.ts.snap | 16 ++---- .../src/type_conversion.ts | 52 ++++++++--------- .../src/orchestrator/orchestrator.test.ts | 5 +- .../src/sequencer/abstract_phase_manager.ts | 4 +- .../src/sequencer/public_processor.test.ts | 14 ++--- .../simulator/src/client/private_execution.ts | 4 +- 49 files changed, 263 insertions(+), 307 deletions(-) diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 9b23244910ee..46b0e92675d2 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -230,15 +230,15 @@ solc-0.8.23 is not recommended for deployment Impact: Informational Confidence: Medium - [ ] ID-24 -Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L130) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L123) +Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L129) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L122) -src/core/libraries/ConstantsGen.sol#L130 +src/core/libraries/ConstantsGen.sol#L129 - [ ] ID-25 -Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L110) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L111) +Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L109) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L110) -src/core/libraries/ConstantsGen.sol#L110 +src/core/libraries/ConstantsGen.sol#L109 - [ ] ID-26 diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index eef15664c7f4..0edddc0d391a 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -72,7 +72,6 @@ library Constants { uint256 internal constant L1_TO_L2_MSG_SUBTREE_HEIGHT = 4; uint256 internal constant L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH = 12; uint256 internal constant FUNCTION_SELECTOR_NUM_BYTES = 4; - uint256 internal constant NUM_FIELDS_PER_SHA256 = 1; uint256 internal constant ARGS_HASH_CHUNK_LENGTH = 32; uint256 internal constant ARGS_HASH_CHUNK_COUNT = 32; uint256 internal constant INITIALIZATION_SLOT_SEPARATOR = 1000_000_000; diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index e81ec725f40a..f02a3a8350a8 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -24,8 +24,7 @@ use dep::protocol_types::{ MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH + MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, RETURN_VALUES_LENGTH }, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, grumpkin_private_key::GrumpkinPrivateKey, hash::hash_args, header::Header, @@ -153,8 +152,8 @@ impl PrivateContext { pub fn finish(self) -> PrivateCircuitPublicInputs { // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - let encrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; - let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; + let encrypted_logs_hash = 0; + let unencrypted_logs_hash = 0; let encrypted_log_preimages_length = 0; let unencrypted_log_preimages_length = 0; @@ -461,7 +460,7 @@ impl PrivateContext { new_l2_to_l1_msgs: [L2ToL1Message::empty(); MAX_NEW_L2_TO_L1_MSGS_PER_CALL], start_side_effect_counter: 0, end_side_effect_counter: 0, - unencrypted_logs_hash: [0; NUM_FIELDS_PER_SHA256], + unencrypted_logs_hash: 0, unencrypted_log_preimages_length: 0, historical_header: Header::empty(), prover_address: AztecAddress::zero(), diff --git a/noir-projects/aztec-nr/aztec/src/context/public_context.nr b/noir-projects/aztec-nr/aztec/src/context/public_context.nr index a8d85a67c854..42a9ed900f69 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -15,8 +15,7 @@ use dep::protocol_types::{ MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH + MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, RETURN_VALUES_LENGTH }, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, hash::hash_args, header::Header, messaging::l2_to_l1_message::L2ToL1Message, utils::reader::Reader @@ -39,8 +38,8 @@ struct PublicContext { new_nullifiers: BoundedVec, new_l2_to_l1_msgs: BoundedVec, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - unencrypted_logs_hash: BoundedVec, + + unencrypted_logs_hash: Field, unencrypted_logs_preimages_length: Field, // Header of a block whose state is used during public execution. Set by sequencer to be a header of a block @@ -64,7 +63,7 @@ impl PublicContext { new_note_hashes: BoundedVec::new(), new_nullifiers: BoundedVec::new(), new_l2_to_l1_msgs: BoundedVec::new(), - unencrypted_logs_hash: BoundedVec::new(), + unencrypted_logs_hash: 0, unencrypted_logs_preimages_length: 0, historical_header: inputs.historical_header, prover_address: AztecAddress::zero() // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) @@ -121,7 +120,7 @@ impl PublicContext { pub fn finish(self) -> PublicCircuitPublicInputs { // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; + let unencrypted_logs_hash = 0; let unencrypted_log_preimages_length = 0; // Compute the public call stack hashes diff --git a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr index 01751c1d3b65..7335cbec6ea8 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::{address::AztecAddress, constants::NUM_FIELDS_PER_SHA256, grumpkin_point::GrumpkinPoint}; +use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}; // TODO: Should take encrypted data. #[oracle(emitEncryptedLog)] @@ -16,8 +16,7 @@ unconstrained pub fn emit_encrypted_log( note_type_id: Field, encryption_pub_key: GrumpkinPoint, preimage: [Field; N] -) -> [Field; NUM_FIELDS_PER_SHA256] { - [ +) -> Field { emit_encrypted_log_oracle( contract_address, storage_slot, @@ -25,7 +24,6 @@ unconstrained pub fn emit_encrypted_log( encryption_pub_key, preimage ) - ] } #[oracle(emitUnencryptedLog)] @@ -39,7 +37,7 @@ unconstrained pub fn emit_unencrypted_log( contract_address: AztecAddress, event_selector: Field, message: T -) -> [Field; NUM_FIELDS_PER_SHA256] { +) -> Field { // https://github.com/AztecProtocol/aztec-packages/issues/885 - [emit_unencrypted_log_oracle(contract_address, event_selector, message)] + emit_unencrypted_log_oracle(contract_address, event_selector, message) } diff --git a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/utils/sha256_merkle_tree.nr b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/utils/sha256_merkle_tree.nr index 14a60b60dbbf..0e969cd3fb3f 100644 --- a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/utils/sha256_merkle_tree.nr +++ b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/utils/sha256_merkle_tree.nr @@ -26,7 +26,7 @@ impl Sha256MerkleTree { leaves[2*i], leaves[2*i+1] ] - )[0]; + ); } // hash the other layers @@ -36,7 +36,7 @@ impl Sha256MerkleTree { nodes[2*i], nodes[2*i+1] ] - )[0]; + ); } Sha256MerkleTree { leaves, nodes } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr index bfc96d831ad9..9495ac896ab2 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr @@ -158,9 +158,9 @@ mod tests { let mut builder = PrivateKernelInitInputsBuilder::new(); // Logs for the private call. - let encrypted_logs_hash = [16]; + let encrypted_logs_hash = 16; let encrypted_log_preimages_length = 100; - let unencrypted_logs_hash = [26]; + let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; builder.private_call.set_encrypted_logs(encrypted_logs_hash, encrypted_log_preimages_length); builder.private_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); @@ -176,10 +176,10 @@ mod tests { assert_eq(public_inputs.end.unencrypted_log_preimages_length, unencrypted_log_preimages_length); // Logs hashes should be a sha256 hash of a 0 value (the previous log hash) and the `(un)encrypted_logs_hash` from private input - let expected_encrypted_logs_hash = compute_logs_hash([0], encrypted_logs_hash); + let expected_encrypted_logs_hash = compute_logs_hash(0, encrypted_logs_hash); assert_eq(public_inputs.end.encrypted_logs_hash, expected_encrypted_logs_hash); - let expected_unencrypted_logs_hash = compute_logs_hash([0], unencrypted_logs_hash); + let expected_unencrypted_logs_hash = compute_logs_hash(0, unencrypted_logs_hash); assert_eq(public_inputs.end.unencrypted_logs_hash, expected_unencrypted_logs_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr index db5a167a1a36..85ad6eb7d898 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr @@ -643,17 +643,17 @@ mod tests { let mut builder = PrivateKernelInnerInputsBuilder::new(); // Logs for the current call stack. - let encrypted_logs_hash = [16]; + let encrypted_logs_hash = 16; let encrypted_log_preimages_length = 100; - let unencrypted_logs_hash = [26]; + let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; builder.private_call.set_encrypted_logs(encrypted_logs_hash, encrypted_log_preimages_length); builder.private_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); // Logs for the previous call stack. - let prev_encrypted_logs_hash = [80]; + let prev_encrypted_logs_hash = 80; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956]; + let prev_unencrypted_logs_hash = 956; let prev_unencrypted_log_preimages_length = 24; builder.previous_kernel.set_encrypted_logs(prev_encrypted_logs_hash, prev_encrypted_log_preimages_length); builder.previous_kernel.set_unencrypted_logs( diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr index abcb33195e32..6904839cecf6 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr @@ -12,7 +12,7 @@ use dep::types::{ MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_CALL, NUM_FIELDS_PER_SHA256, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }, @@ -429,7 +429,7 @@ fn propagate_new_l2_to_l1_messages(public_call: PublicCallData, public_inputs: & */ pub fn accumulate_unencrypted_logs( public_call: PublicCallData, - previous_unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + previous_unencrypted_logs_hash: Field, previous_unencrypted_log_preimages_length: Field, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder ) { @@ -437,8 +437,8 @@ pub fn accumulate_unencrypted_logs( let current_unencrypted_logs_hash = public_call_public_inputs.unencrypted_logs_hash; public_inputs.end.unencrypted_logs_hash = accumulate_sha256([ - previous_unencrypted_logs_hash[0], - current_unencrypted_logs_hash[0], + previous_unencrypted_logs_hash, + current_unencrypted_logs_hash, ]); // Add log preimages lengths from current iteration to accumulated lengths diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr index e783994c9a80..db9b23118090 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr @@ -295,14 +295,14 @@ mod tests { fn circuit_outputs_should_be_correctly_populated_with_previous_public_kernel_logs() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); // Logs for the current call stack. - let unencrypted_logs_hash = [26]; + let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; builder.public_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); // Logs for the previous call stack. - let prev_encrypted_logs_hash = [80]; + let prev_encrypted_logs_hash = 80; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956]; + let prev_unencrypted_logs_hash = 956; let prev_unencrypted_log_preimages_length = 24; builder.previous_kernel.set_encrypted_logs(prev_encrypted_logs_hash, prev_encrypted_log_preimages_length); builder.previous_kernel.set_unencrypted_logs( diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr index cff94ecab8ee..ccc53377fedc 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr @@ -450,14 +450,14 @@ mod tests { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); // Logs for the current call stack. - let unencrypted_logs_hash = [26]; + let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; builder.public_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); // Logs for the previous call stack. - let prev_encrypted_logs_hash = [80]; + let prev_encrypted_logs_hash = 80; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956]; + let prev_unencrypted_logs_hash = 956; let prev_unencrypted_log_preimages_length = 24; builder.previous_kernel.set_encrypted_logs(prev_encrypted_logs_hash, prev_encrypted_log_preimages_length); builder.previous_kernel.set_unencrypted_logs( diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr index 3f301d0da55a..85409d64a6c5 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr @@ -343,14 +343,14 @@ mod tests { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); // Logs for the current call stack. - let unencrypted_logs_hash = [26]; + let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; builder.public_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); // Logs for the previous call stack. - let prev_encrypted_logs_hash = [80]; + let prev_encrypted_logs_hash = 80; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956]; + let prev_unencrypted_logs_hash = 956; let prev_unencrypted_log_preimages_length = 24; builder.previous_kernel.set_encrypted_logs(prev_encrypted_logs_hash, prev_encrypted_log_preimages_length); builder.previous_kernel.set_unencrypted_logs( diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr index bf5b8d528de6..15f33302d755 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr @@ -1,5 +1,5 @@ use dep::types::{ - abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, constants::NUM_FIELDS_PER_SHA256, + abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, partial_state_reference::PartialStateReference }; use crate::abis::constant_rollup_data::ConstantRollupData; @@ -26,6 +26,6 @@ struct BaseOrMergeRollupPublicInputs { // So we want to constrain it when casting these fields to U128 // We hash public inputs to make them constant-sized (to then be unpacked on-chain) - txs_effects_hash : [Field; NUM_FIELDS_PER_SHA256], - out_hash : [Field; NUM_FIELDS_PER_SHA256], + txs_effects_hash : Field, + out_hash : Field, } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index 6ca8dbd1eacb..b8be6406f0ac 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -17,7 +17,7 @@ use dep::types::{ }, constants::{ NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, - PUBLIC_DATA_TREE_HEIGHT, NOTE_HASH_SUBTREE_HEIGHT, NUM_FIELDS_PER_SHA256, + PUBLIC_DATA_TREE_HEIGHT, NOTE_HASH_SUBTREE_HEIGHT, MAX_NEW_NOTE_HASHES_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, NUM_ENCRYPTED_LOGS_HASHES_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_UNENCRYPTED_LOGS_HASHES_PER_TX, NULLIFIER_SUBTREE_HEIGHT, NULLIFIER_TREE_HEIGHT, @@ -396,7 +396,7 @@ mod tests { MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, NOTE_HASH_TREE_HEIGHT, NOTE_HASH_SUBTREE_HEIGHT, NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_TREE_HEIGHT, NULLIFIER_SUBTREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, - PUBLIC_DATA_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, NUM_FIELDS_PER_SHA256, + PUBLIC_DATA_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, MAX_NEW_L2_TO_L1_MSGS_PER_TX }, contract_class_id::ContractClassId, partial_state_reference::PartialStateReference, @@ -941,10 +941,8 @@ mod tests { let hash_input_flattened = [0; TX_EFFECTS_HASH_INPUT_FIELDS * 32]; let sha_digest = dep::std::hash::sha256(hash_input_flattened); - let expected_tx_effects_hash = [field_from_bytes_32_trunc(sha_digest)]; - for i in 0..NUM_FIELDS_PER_SHA256 { - assert_eq(outputs.txs_effects_hash[i], expected_tx_effects_hash[i]); - } + let expected_tx_effects_hash = field_from_bytes_32_trunc(sha_digest); + assert_eq(outputs.txs_effects_hash, expected_tx_effects_hash); } #[test] @@ -953,10 +951,8 @@ mod tests { let hash_input_flattened = [0; MAX_NEW_L2_TO_L1_MSGS_PER_TX * 32]; let sha_digest = dep::std::hash::sha256(hash_input_flattened); - let expected_out_hash = [field_from_bytes_32_trunc(sha_digest)]; - for i in 0..NUM_FIELDS_PER_SHA256 { - assert_eq(outputs.out_hash[i], expected_out_hash[i]); - } + let expected_out_hash = field_from_bytes_32_trunc(sha_digest); + assert_eq(outputs.out_hash, expected_out_hash); } #[test] @@ -969,11 +965,8 @@ mod tests { let mut hash_input_flattened = [0; MAX_NEW_L2_TO_L1_MSGS_PER_TX * 32]; hash_input_flattened[MAX_NEW_L2_TO_L1_MSGS_PER_TX * 32 - 1] = 123; let sha_digest = dep::std::hash::sha256(hash_input_flattened); - let expected_out_hash = [field_from_bytes_32_trunc(sha_digest)]; - - for i in 0..NUM_FIELDS_PER_SHA256 { - assert_eq(out_hash[i], expected_out_hash[i]); - } + let expected_out_hash = field_from_bytes_32_trunc(sha_digest); + assert_eq(out_hash, expected_out_hash); } #[test(should_fail_with = "membership check failed")] diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr index 72e2c47b46c0..aaa831998022 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr @@ -3,7 +3,7 @@ use crate::abis::previous_rollup_data::PreviousRollupData; use dep::types::{ mocked::AggregationObject, hash::accumulate_sha256, constants::{ - NUM_FIELDS_PER_SHA256, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_UNENCRYPTED_LOGS_HASHES_PER_TX, NUM_ENCRYPTED_LOGS_HASHES_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }, @@ -79,24 +79,22 @@ pub fn assert_prev_rollups_follow_on_from_each_other( ); } -// TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - /** * @brief From two previous rollup data, compute a single out hash * * @param previous_rollup_data * @return out hash stored in 2 fields */ -pub fn compute_out_hash(previous_rollup_data: [PreviousRollupData; 2]) -> [Field; NUM_FIELDS_PER_SHA256] { +pub fn compute_out_hash(previous_rollup_data: [PreviousRollupData; 2]) -> Field { accumulate_sha256( [ - previous_rollup_data[0].base_or_merge_rollup_public_inputs.out_hash[0], - previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash[0], + previous_rollup_data[0].base_or_merge_rollup_public_inputs.out_hash, + previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash, ] ) } -pub fn compute_kernel_out_hash(combined: CombinedAccumulatedData) -> [Field; NUM_FIELDS_PER_SHA256] { +pub fn compute_kernel_out_hash(combined: CombinedAccumulatedData) -> Field { let mut out_hash_inputs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX] = combined.new_l2_to_l1_msgs; let mut hash_input_flattened = [0; MAX_NEW_L2_TO_L1_MSGS_PER_TX * 32]; @@ -108,7 +106,7 @@ pub fn compute_kernel_out_hash(combined: CombinedAccumulatedData) -> [Field; NUM } let sha_digest = dep::types::hash::sha256_to_field(hash_input_flattened); - [sha_digest] + sha_digest } /** @@ -117,11 +115,11 @@ pub fn compute_kernel_out_hash(combined: CombinedAccumulatedData) -> [Field; NUM * @param previous_rollup_data * @return The hash of the transaction effects stored in 2 fields */ -pub fn compute_txs_effects_hash(previous_rollup_data: [PreviousRollupData; 2]) -> [Field; NUM_FIELDS_PER_SHA256] { +pub fn compute_txs_effects_hash(previous_rollup_data: [PreviousRollupData; 2]) -> Field { accumulate_sha256( [ - previous_rollup_data[0].base_or_merge_rollup_public_inputs.txs_effects_hash[0], - previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash[0], + previous_rollup_data[0].base_or_merge_rollup_public_inputs.txs_effects_hash, + previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash, ] ) } @@ -130,7 +128,7 @@ global TX_EFFECTS_HASH_INPUT_FIELDS = 197; // Computes the tx effects hash for a base rollup (a single transaction) // TODO(Alvaro): This is too slow for brillig without the array optimization -pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM_FIELDS_PER_SHA256] { +pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> Field { // Compute tx effect hash // Consist of // MAX_NEW_NOTE_HASHES_PER_TX fields for note hashes @@ -179,17 +177,13 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM } offset += MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2; - for j in 0..NUM_FIELDS_PER_SHA256 { - txs_effects_hash_input[offset + j] = encryptedLogsHash[j]; - } + txs_effects_hash_input[offset] = encryptedLogsHash; - offset += NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + offset += NUM_ENCRYPTED_LOGS_HASHES_PER_TX; - for j in 0..NUM_FIELDS_PER_SHA256 { - txs_effects_hash_input[offset + j] = unencryptedLogsHash[j]; - } + txs_effects_hash_input[offset] = unencryptedLogsHash; - offset += NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + offset += NUM_UNENCRYPTED_LOGS_HASHES_PER_TX; assert_eq(offset, TX_EFFECTS_HASH_INPUT_FIELDS); // Sanity check let mut hash_input_flattened = [0; TX_EFFECTS_HASH_INPUT_FIELDS * 32]; @@ -201,7 +195,7 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM } let sha_digest = dep::types::hash::sha256_to_field(hash_input_flattened); - [sha_digest] + sha_digest } #[test] @@ -212,7 +206,7 @@ fn consistent_TX_EFFECTS_HASH_INPUT_FIELDS() { + MAX_NEW_NULLIFIERS_PER_TX + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2 + MAX_NEW_L2_TO_L1_MSGS_PER_TX - + NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256 - + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + + NUM_ENCRYPTED_LOGS_HASHES_PER_TX + + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX; assert(TX_EFFECTS_HASH_INPUT_FIELDS == expected_size, "tx effects hash input size is incorrect"); } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root.nr index 2a7dbfa4c9b0..3784e95d63bb 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root.nr @@ -6,7 +6,7 @@ use root_rollup_inputs::RootRollupInputs; use root_rollup_public_inputs::RootRollupPublicInputs; // TODO: Move all the following code to different files -use dep::types::{constants::{NUM_FIELDS_PER_SHA256, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP}, utils::uint256::U256, hash::sha256_to_field}; +use dep::types::{constants::NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, utils::uint256::U256, hash::sha256_to_field}; // See `test_message_input_flattened_length` on keeping this in sync, // why its here and how this constant was computed. @@ -16,7 +16,7 @@ global NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP_NUM_BYTES: u64 = 512; // // TODO(Miranda): remove? This appears to be unused // Returns the hash truncated to one field element -fn compute_messages_hash(leaves: [Field; NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP]) -> [Field; NUM_FIELDS_PER_SHA256] { +fn compute_messages_hash(leaves: [Field; NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP]) -> Field { // Slice variation // let mut hash_input_flattened = []; // for leaf in leaves { @@ -36,7 +36,7 @@ fn compute_messages_hash(leaves: [Field; NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP]) - } } - [sha256_to_field(hash_input_flattened)] + sha256_to_field(hash_input_flattened) } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr index f14909664eb8..4e87655b8f84 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr @@ -61,7 +61,7 @@ impl RootRollupInputs { let content_commitment = ContentCommitment { tx_tree_height: right.height_in_block_tree + 1, txs_effects_hash: components::compute_txs_effects_hash(self.previous_rollup_data), - in_hash: [self.l1_to_l2_roots.public_inputs.sha_root], + in_hash: self.l1_to_l2_roots.public_inputs.sha_root, out_hash: components::compute_out_hash(self.previous_rollup_data) }; diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr index 9ef6c6920ee9..3185a6bfdb7b 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr @@ -62,11 +62,11 @@ pub fn default_previous_rollup_data() -> [PreviousRollupData; 2] { previous_rollup_data[0].base_or_merge_rollup_public_inputs.height_in_block_tree = 1; previous_rollup_data[1].base_or_merge_rollup_public_inputs.height_in_block_tree = 1; - previous_rollup_data[0].base_or_merge_rollup_public_inputs.txs_effects_hash = [1]; - previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash = [2]; + previous_rollup_data[0].base_or_merge_rollup_public_inputs.txs_effects_hash = 1; + previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash = 2; - previous_rollup_data[0].base_or_merge_rollup_public_inputs.out_hash = [1]; - previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash = [2]; + previous_rollup_data[0].base_or_merge_rollup_public_inputs.out_hash = 1; + previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash = 2; previous_rollup_data } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr index 738b2b7706dc..232ebbc81bc0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr @@ -9,7 +9,7 @@ use crate::{ } }; use crate::constants::{ - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; @@ -21,9 +21,9 @@ struct AccumulatedRevertibleDataBuilder { private_call_stack: BoundedVec, public_call_stack: BoundedVec, new_l2_to_l1_msgs: BoundedVec, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr index 8c8ac82db33e..76f7e00531f8 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr @@ -12,7 +12,7 @@ use crate::{ use crate::constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256 + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; use dep::std::unsafe; @@ -29,9 +29,9 @@ struct CombinedAccumulatedData { private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX], new_l2_to_l1_msgs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX], - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr index 53aad2456a37..f72d34c9565a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr @@ -16,7 +16,7 @@ use crate::{ use crate::constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256 + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; use dep::std::unsafe; @@ -33,9 +33,9 @@ struct CombinedAccumulatedDataBuilder { private_call_stack: BoundedVec, public_call_stack: BoundedVec, new_l2_to_l1_msgs: BoundedVec, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_revertible_data.nr index 8c6874e6749a..9144bd52a221 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_revertible_data.nr @@ -2,7 +2,7 @@ use crate::{abis::{call_request::CallRequest, side_effect::{SideEffect, SideEffe use crate::constants::{ MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256 + MAX_NEW_L2_TO_L1_MSGS_PER_TX }; struct PrivateAccumulatedRevertibleData { @@ -12,9 +12,9 @@ struct PrivateAccumulatedRevertibleData { private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest; MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX], new_l2_to_l1_msgs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX], - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr index 777457eb4ddd..3b3c21a9067a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr @@ -7,7 +7,7 @@ use crate::{ use crate::constants::{ MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; @@ -18,9 +18,9 @@ struct PublicAccumulatedRevertibleData { private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest; MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX], new_l2_to_l1_msgs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX], - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr index 8bcaa685a508..d28856d42c93 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr @@ -7,7 +7,7 @@ use crate::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, NUM_FIELDS_PER_SHA256, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, RETURN_VALUES_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS }, @@ -35,9 +35,8 @@ struct PrivateCircuitPublicInputs { start_side_effect_counter : u32, end_side_effect_counter : u32, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. @@ -110,8 +109,8 @@ impl Serialize for PrivateCircuitPublicInp } fields.push(self.start_side_effect_counter as Field); fields.push(self.end_side_effect_counter as Field); - fields.extend_from_array(self.encrypted_logs_hash); - fields.extend_from_array(self.unencrypted_logs_hash); + fields.push(self.encrypted_logs_hash); + fields.push(self.unencrypted_logs_hash); fields.push(self.encrypted_log_preimages_length); fields.push(self.unencrypted_log_preimages_length); fields.extend_from_array(self.historical_header.serialize()); @@ -143,8 +142,8 @@ impl Deserialize for PrivateCircuitPublicI new_l2_to_l1_msgs: reader.read_struct_array(L2ToL1Message::deserialize, [L2ToL1Message::empty(); MAX_NEW_L2_TO_L1_MSGS_PER_CALL]), start_side_effect_counter: reader.read() as u32, end_side_effect_counter: reader.read() as u32, - encrypted_logs_hash: reader.read_array([0; NUM_FIELDS_PER_SHA256]), - unencrypted_logs_hash: reader.read_array([0; NUM_FIELDS_PER_SHA256]), + encrypted_logs_hash: reader.read() as Field, + unencrypted_logs_hash: reader.read() as Field, encrypted_log_preimages_length: reader.read(), unencrypted_log_preimages_length: reader.read(), historical_header: reader.read_struct(Header::deserialize), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr index a243b7a3dfbe..dab7f2b7fcf7 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr @@ -8,7 +8,7 @@ use crate::{ MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, RETURN_VALUES_LENGTH, GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS, PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH }, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, @@ -35,8 +35,8 @@ struct PublicCircuitPublicInputs{ start_side_effect_counter: u32, end_side_effect_counter: u32, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. @@ -90,7 +90,7 @@ impl Serialize for PublicCircuitPublicInput fields.push(self.start_side_effect_counter as Field); fields.push(self.end_side_effect_counter as Field); - fields.extend_from_array(self.unencrypted_logs_hash); + fields.push(self.unencrypted_logs_hash); fields.push(self.unencrypted_log_preimages_length); fields.extend_from_array(self.historical_header.serialize()); fields.push(self.prover_address.to_field()); @@ -117,7 +117,7 @@ impl Deserialize for PublicCircuitPublicInp new_l2_to_l1_msgs: reader.read_struct_array(L2ToL1Message::deserialize, [L2ToL1Message::empty(); MAX_NEW_L2_TO_L1_MSGS_PER_CALL]), start_side_effect_counter: reader.read() as u32, end_side_effect_counter: reader.read() as u32, - unencrypted_logs_hash: reader.read_array([0; NUM_FIELDS_PER_SHA256]), + unencrypted_logs_hash: reader.read() as Field, unencrypted_log_preimages_length: reader.read(), historical_header: reader.read_struct(Header::deserialize), prover_address: reader.read_struct(AztecAddress::deserialize), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 0e8303246712..9dae6848676a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -96,8 +96,6 @@ global L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH: u64 = 12; // MISC CONSTANTS global FUNCTION_SELECTOR_NUM_BYTES: Field = 4; -// sha256 hash is truncated into a single field -global NUM_FIELDS_PER_SHA256: u64 = 1; global ARGS_HASH_CHUNK_LENGTH: u64 = 32; global ARGS_HASH_CHUNK_COUNT: u64 = 32; // The following is used in immutable state variables to compute an initialization slot whose value is used to diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr b/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr index 5c0061d4e018..8417fa0ea792 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr @@ -1,13 +1,13 @@ use crate::{ - constants::{NUM_FIELDS_PER_SHA256, CONTENT_COMMITMENT_LENGTH}, + constants::CONTENT_COMMITMENT_LENGTH, traits::{Deserialize, Empty, Hash, Serialize}, utils::{arr_copy_slice} }; -// TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 + struct ContentCommitment { tx_tree_height: Field, - txs_effects_hash: [Field; NUM_FIELDS_PER_SHA256], - in_hash: [Field; NUM_FIELDS_PER_SHA256], - out_hash: [Field; NUM_FIELDS_PER_SHA256], + txs_effects_hash: Field, + in_hash: Field, + out_hash: Field, } impl Serialize for ContentCommitment { @@ -15,9 +15,9 @@ impl Serialize for ContentCommitment { let mut fields: BoundedVec = BoundedVec::new(); fields.extend_from_array([self.tx_tree_height]); - fields.extend_from_array(self.txs_effects_hash); - fields.extend_from_array(self.in_hash); - fields.extend_from_array(self.out_hash); + fields.extend_from_array([self.txs_effects_hash]); + fields.extend_from_array([self.in_hash]); + fields.extend_from_array([self.out_hash]); fields.storage } @@ -26,15 +26,12 @@ impl Serialize for ContentCommitment { impl Deserialize for ContentCommitment { fn deserialize(serialized: [Field; CONTENT_COMMITMENT_LENGTH]) -> Self { let tx_tree_height = serialized[0]; - let mut offset = 1; - let txs_effects_hash = arr_copy_slice(serialized, [0; NUM_FIELDS_PER_SHA256], offset); - offset = offset + NUM_FIELDS_PER_SHA256; + let txs_effects_hash = serialized[1]; - let in_hash = arr_copy_slice(serialized, [0; NUM_FIELDS_PER_SHA256], offset); - offset = offset + NUM_FIELDS_PER_SHA256; + let in_hash = serialized[2]; - let out_hash = arr_copy_slice(serialized, [0; NUM_FIELDS_PER_SHA256], offset); + let out_hash = serialized[3]; Self { tx_tree_height, @@ -49,9 +46,9 @@ impl Empty for ContentCommitment { fn empty() -> Self { Self { tx_tree_height: 0, - txs_effects_hash: [0; NUM_FIELDS_PER_SHA256], - in_hash: [0; NUM_FIELDS_PER_SHA256], - out_hash: [0; NUM_FIELDS_PER_SHA256], + txs_effects_hash: 0, + in_hash: 0, + out_hash: 0, } } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr index fbb6996c78d0..cc0948346ef2 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr @@ -6,7 +6,7 @@ use crate::contract_class_id::ContractClassId; use crate::abis::side_effect::{SideEffect}; use crate::utils::{uint256::U256, field::field_from_bytes_32_trunc}; use crate::constants::{ - ARGS_HASH_CHUNK_COUNT, ARGS_HASH_CHUNK_LENGTH, FUNCTION_TREE_HEIGHT, NUM_FIELDS_PER_SHA256, + ARGS_HASH_CHUNK_COUNT, ARGS_HASH_CHUNK_LENGTH, FUNCTION_TREE_HEIGHT, GENERATOR_INDEX__SILOED_NOTE_HASH, GENERATOR_INDEX__OUTER_NULLIFIER, GENERATOR_INDEX__VK, GENERATOR_INDEX__CONSTRUCTOR, GENERATOR_INDEX__PARTIAL_ADDRESS, GENERATOR_INDEX__CONTRACT_ADDRESS, GENERATOR_INDEX__NOTE_HASH_NONCE, GENERATOR_INDEX__UNIQUE_NOTE_HASH, GENERATOR_INDEX__FUNCTION_ARGS @@ -119,9 +119,8 @@ pub fn compute_l2_to_l1_hash( // // TODO(Jan and David): This is used for the encrypted_log hashes. // Can we check to see if we can just use hash_to_field or pedersen_compress here? -// TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 // -pub fn accumulate_sha256(input: [Field; NUM_FIELDS_PER_SHA256 * 2]) -> [Field; NUM_FIELDS_PER_SHA256] { +pub fn accumulate_sha256(input: [Field; 2]) -> Field { // This is a note about the cpp code, since it takes an array of Fields // instead of a U128. // 4 Field elements when converted to bytes will usually @@ -141,17 +140,17 @@ pub fn accumulate_sha256(input: [Field; NUM_FIELDS_PER_SHA256 * 2]) -> [Field; N } } - [sha256_to_field(hash_input_flattened)] + sha256_to_field(hash_input_flattened) } pub fn compute_logs_hash( - previous_log_hash: [Field; NUM_FIELDS_PER_SHA256], - current_log_hash: [Field; NUM_FIELDS_PER_SHA256] -) -> [Field; NUM_FIELDS_PER_SHA256] { + previous_log_hash: Field, + current_log_hash: Field +) -> Field { accumulate_sha256( [ - previous_log_hash[0], - current_log_hash[0] + previous_log_hash, + current_log_hash ] ) } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr index 08885205e2d3..35c4410fc3c4 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr @@ -18,7 +18,7 @@ use crate::{ }; use crate::constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256, + MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, VK_TREE_HEIGHT }; use dep::std::unsafe; @@ -230,12 +230,12 @@ impl PreviousKernelDataBuilder { self.min_revertible_side_effect_counter = self.sideffect_counter; } - pub fn set_encrypted_logs(&mut self, hash: [Field; NUM_FIELDS_PER_SHA256], preimages_length: Field) { + pub fn set_encrypted_logs(&mut self, hash: Field, preimages_length: Field) { self.end.encrypted_logs_hash = hash; self.end.encrypted_log_preimages_length = preimages_length; } - pub fn set_unencrypted_logs(&mut self, hash: [Field; NUM_FIELDS_PER_SHA256], preimages_length: Field) { + pub fn set_unencrypted_logs(&mut self, hash: Field, preimages_length: Field) { self.end.unencrypted_logs_hash = hash; self.end.unencrypted_log_preimages_length = preimages_length; } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr index 75422217f4f4..b7ac9cc6cc08 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr @@ -16,7 +16,7 @@ use crate::{ }; use crate::constants::{ MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256 + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL }; struct PrivateCallDataBuilder { @@ -151,12 +151,12 @@ impl PrivateCallDataBuilder { self.note_hash_read_request_membership_witnesses.extend_from_bounded_vec(read_request_membership_witnesses); } - pub fn set_encrypted_logs(&mut self, hash: [Field; NUM_FIELDS_PER_SHA256], preimages_length: Field) { + pub fn set_encrypted_logs(&mut self, hash: Field, preimages_length: Field) { self.public_inputs.encrypted_logs_hash = hash; self.public_inputs.encrypted_log_preimages_length = preimages_length; } - pub fn set_unencrypted_logs(&mut self, hash: [Field; NUM_FIELDS_PER_SHA256], preimages_length: Field) { + pub fn set_unencrypted_logs(&mut self, hash: Field, preimages_length: Field) { self.public_inputs.unencrypted_logs_hash = hash; self.public_inputs.unencrypted_log_preimages_length = preimages_length; } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr index 1c3f4c344f8e..616e1dbcdc8a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr @@ -11,7 +11,7 @@ use crate::constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, NUM_FIELDS_PER_SHA256, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, RETURN_VALUES_LENGTH }; @@ -33,9 +33,9 @@ struct PrivateCircuitPublicInputsBuilder { private_call_stack_hashes: BoundedVec, public_call_stack_hashes: BoundedVec, new_l2_to_l1_msgs: BoundedVec, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, encrypted_log_preimages_length: Field, unencrypted_log_preimages_length: Field, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr index f10579958e5b..e71ac9550206 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr @@ -10,7 +10,7 @@ use crate::{ }; use crate::constants::{ MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256 + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL }; struct PublicCallDataBuilder { @@ -147,7 +147,7 @@ impl PublicCallDataBuilder { } } - pub fn set_unencrypted_logs(&mut self, hash: [Field; NUM_FIELDS_PER_SHA256], preimages_length: Field) { + pub fn set_unencrypted_logs(&mut self, hash: Field, preimages_length: Field) { self.public_inputs.unencrypted_logs_hash = hash; self.public_inputs.unencrypted_log_preimages_length = preimages_length; } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr index 169cfb4bcd4c..c033915b4b9f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr @@ -11,7 +11,7 @@ use crate::constants::{ MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, RETURN_VALUES_LENGTH }; struct PublicCircuitPublicInputsBuilder { @@ -28,8 +28,7 @@ struct PublicCircuitPublicInputsBuilder { new_l2_to_l1_msgs: BoundedVec, start_side_effect_counter: u32, end_side_effect_counter: u32, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + unencrypted_logs_hash: Field, unencrypted_log_preimages_length: Field, historical_header: Header, prover_address: AztecAddress, diff --git a/yarn-project/circuit-types/src/mocks_to_purge.ts b/yarn-project/circuit-types/src/mocks_to_purge.ts index 28cb2a2c292a..a7c9903cf9bb 100644 --- a/yarn-project/circuit-types/src/mocks_to_purge.ts +++ b/yarn-project/circuit-types/src/mocks_to_purge.ts @@ -20,7 +20,6 @@ import { MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - NUM_FIELDS_PER_SHA256, Point, PrivateAccumulatedNonRevertibleData, PrivateAccumulatedRevertibleData, @@ -145,8 +144,8 @@ export function makeFinalAccumulatedData(seed = 1, full = false): PrivateAccumul tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), tupleGenerator(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x500), tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x600), - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x800), // unencrypted logs hash + fr(seed + 0x700), // encrypted logs hash + fr(seed + 0x800), // unencrypted logs hash fr(seed + 0x900), // encrypted_log_preimages_length fr(seed + 0xa00), // unencrypted_log_preimages_length ); diff --git a/yarn-project/circuit-types/src/tx/processed_tx.ts b/yarn-project/circuit-types/src/tx/processed_tx.ts index d8368e273709..50db53e96a77 100644 --- a/yarn-project/circuit-types/src/tx/processed_tx.ts +++ b/yarn-project/circuit-types/src/tx/processed_tx.ts @@ -192,7 +192,7 @@ export function toTxEffect(tx: ProcessedTx): TxEffect { function validateProcessedTxLogs(tx: ProcessedTx): void { const unencryptedLogs = tx.unencryptedLogs || new TxL2Logs([]); - const kernelUnencryptedLogsHash = tx.data.combinedData.unencryptedLogsHash[0]; + const kernelUnencryptedLogsHash = tx.data.combinedData.unencryptedLogsHash; const referenceHash = toTruncField(unencryptedLogs.hash())[0]; if (!referenceHash.equals(kernelUnencryptedLogsHash)) { throw new Error( diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index f9e907a3dbb5..93e85edd3821 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -58,7 +58,6 @@ export const PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH = 35; export const L1_TO_L2_MSG_SUBTREE_HEIGHT = 4; export const L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH = 12; export const FUNCTION_SELECTOR_NUM_BYTES = 4; -export const NUM_FIELDS_PER_SHA256 = 1; export const ARGS_HASH_CHUNK_LENGTH = 32; export const ARGS_HASH_CHUNK_COUNT = 32; export const INITIALIZATION_SLOT_SEPARATOR = 1000_000_000; diff --git a/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap b/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap index d0b5e308a320..dfc593aef670 100644 --- a/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap +++ b/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap @@ -9,18 +9,18 @@ exports[`ContractClass creates a contract class from a contract compilation arti "selector": { "value": 2381782501 }, - "bytecode": "0x1f8b08000000000000ffed9d77781447baee5b20e22001ced9c2f6ae033616424409189c73c6c618631002830d88689c713639384772cec1648c0163eccdd9bbeb0db677d71bce7dee73ef9fe79c7b8fefed9aa9efe8a5a81e3472d7f04a53fd3ca5a9fe54dddfafdefeba3a55771504e9e95f612ad0f9a661ba20387a92ff27f56fe9779b3ac7b8ae52979c050d84b34903e16cda40380b1b0867b306c2d9bc8170b668209c2d1b0867ab18390b80cf156feb06c69b6860bc6d828611b7450d84b3b88170b66d209ced1a0867fb06c2794203e13cb181709ed440384f6e209ca73410ce531b08e7690d84f3f406c2794603e13cb381709ed54038cf6e209ce73410ce731b08674903e1ecd04038cf6b209ce7c7c8d91138e55efef7f4eff7f5ef85faf722fd7bb1febd44ff76d4752cd4f39786e9b230750ad3e5c6ff9430ea867e5998ba18ff2b0f53d730750b5377fdbf12fdbf1e61ea19a65e61aa085365987a87a94f98fa6a3dfa85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bbc2d43f4c7787e91e83654098ee0dd3c030dd17a64161ba3f4c83c3f440988684696898aac2342c4cd5611a1ea611617a304c23c3342a4c0f85e9e1308d0ed398308d0d534d98c685697c98268469629826856972981e09d31443b347c3f458981e0fd31306e793617a2a4c4f87696a989e09d3b3617a2e4ccf87e98530bd18a697c2f47298a685697a9866846966986685697698e684696e98e685697e985e09d3ab617a2d4caf87e98d30bd19a6b7c2f47698de09d3bb9a457684f7c2f47e98168469619816856971989684696998968569799856846965985685697598d684696d98d685697d9836846963983685697398b684696b983e08d3b6306d0fd38e30ed0cd3ae30ed0ed39e30ed0dd38761da17a68fc2b43f4c07c274304c1f87e950983e09d3e1307d1aa6cfc2f48330fd304c3f3234ff71987e12a69f86e967daf673fdfb0b5d56f6f95feadf5fe9df5febdfdfe8dfcf8df2bf35e67f67ccff5eff7ea17fffa07fffa87fffa47fffac7fbfd4bf5fe9dfaff5ef5ff4ef5ff5efdff4ef37faf7effaf71ffaf79ffa573dff7bb5433adf32a89d92414c6d52f9f0a1eafebf886d3e5f54cfae9aeaffc96f89b617ea79f92dd0f6667abe99616faee79b1beb69a9e75b1af6623d5f6cd8dbe9f97686fd043d7f82613f49cf9f64d83be8f90e604fe8ffa52b96fe51b6a6da54003689cf26606ba66d4dc1d65c5607b616dad60c6cb27d9b83ad95b6b5005b6b6d6b09b684b6b5122dc3d446db92415cb1523a54adb728eef5ea6726c5f1f356a9f5b675c4db2e7ede616abded1df0aaf83841afab08e2e6446d2b06db49dad6166c276b5b3bb09da26dedc176aab69d00b6d3b4ed44b09dae6d2781ed0c6d3b196c676adb29603b4bdb4e05dbd9da761ad8ced1b6d3c176aeb69d01b6126d3b136cbac90dce02db79da7636d8ced7b673c07681b69d0b3639c72b019b9cef75009b9cfb9d0736390f3c5fdb54dbd1aa00fc69bbb45b297fd26683edfbd25e83ed4269abc17691b4d360bb187c8bed12686bc4d651dba4dd52ffeba5f3c920aefda42cb59f54c4bdde70cd6abdbde35f6feaf95d9fa056eb24f8a900adfaea7c8c7d5b3aa36f39b7113f622f84fc0d5056ca891e72ec1176752ca8d4f9be1996eb652c570c652a2df54f06f1d6bfb7c1d3db606e06793731dba5d4c76c9da7ac6376009435634fce831a63ccde0c1c0e62b6dcc76c9da7ac6376049435634fce851b63ccde071c0e62b6879b982d2bf5319bbe371604f6d893eba1c618b3a38023fe98edea63b6ee53d631fb1c9435634fae891b63cc4e018ef863b67b0f7f6e50e729eb989d0765cdd893fb338d31665f040e07313bccb7b3759eb28ed90550d68c3db957d81863f655e0883f667b3a8ad92e3e6683f473ce20b0c79edcb76e8c31bb1838e28fd961fefe6cdda7ac6376379435634f9ea134c698dda8f3ea39c3cff57386b3c0f60b6d3b1b78e38fedea3247b1ddd9c776baff4710d863549ee735c6d8fe48e7551cff0afa2388edd7d257016cbfd1b6f3c0f6b9b69d0ff572b00f74f7fb40ddeb94ed3ef047286bc6b23c5b6e8cfbc02f80c341ccf6f0315bf73a651bb3ff0665cdd8937e0e8d3166bf040e0731dbd3c76cddeb946dccfe3b943563ef229d6f8c31fb3f755e9d2f7ca1cf172e01db1fb4ad23d8fea86d9782ed4fda7619d8feac6d9dc0f6a5b65d0eb6afb4ad146c5f6b5b67b0fd45dbcac0f6576deb02b6bf695b39d8bed1b6ae60fbbbb67503db3fb4ad3bd8fea96d3dc0f62f6deba96daa9f9ef4bd3aac6d2d813f19c4bb6da5dfa5ac5be63be7c0775bc377db1cfa6e6ff86e6ff15de6c077027cc85460cc27215fe696a7b41878d05779fcbebaa8ba7709ea5ef772e0e9eaa0ee09f051179eaec0d32d7e9ed4f1b37bfceb4d6de32e86a609f0d505ead5c341bd0ac097ac5be6c55f31d8b06ded6161ec193f635901f89275cb7c4f60141bb6f5f22e95ec3fea787861412daf837d29754e24fee4db55c2510e76297371875ab68e9aad08fe8fc7bd6e86cd515ca6e2427cc9ba655efc15417dbae59eb1acae8c5d0d46576d4401f892757bdfb5db41f2781c7771ad636bd3c477450e7cf7347c971bbeb1ed9429d3b1ad2730c77ecda98f6d95f1afb714af4fe4da50fce0f9035ec3c55527f42dd786e247ec8590bfa5a0b6ac94133da41d167615cbb22d91dd5cae87b15c3194a9b0d43f19c45bff4a83a7d26056dbe44a38163ad81f5231506170c87c39685719a15d056827652e02ed5cb567bd0c1e99ef063cd28e75071e57d744513cb9b81e3b966f3c87c5eb67f93f9e07b8da5e9d0d4699b76daf9ec0683b5771703d93f15ca52b308aad17f07471a459d476ed42e2db41aca4da23f121e7e6b2ff7603bb94e9a95fa8536de543d056ba88118c4799ea7acd1bff762a4b5d8377cd8207b79d83ebaace8ee2b114efdf7c1bc41b6b66bbd4d5d02aea1e8fabb6bc8bc123f3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f333e4fc27e5b52ae1b09a3d9ffcdd57dfed4370cf5ba64fdeab9ceff71da1facac14fbc7483f884b8c3a174299a226b565ff1ff407339f53611fc96e6eb54b6d4bec8f998479f1877dad705b32f4772a89cd77fa5b942e9eb7a93ed6ea3b9a66dfcf6e164d5df47f464d0b0c4db13ffea5068f8ad3caa6b56c2e9efd65fb2c12b5927c9ccff68a037bacc7bf5dca8e7866dd2438b2fdc0e38cabfe3bd256cbf3f20ac377219439b349edb691be5532ce6c176339ecf723eb96652e017ba5b1ee767a59e16866acbf3b2c2b65ce8136f540935acd1cb49565d9f65dc7e7e6f11f87d3cff1bb64c1d319785cb4338ece378ef8de6adccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c8431477d1f52cf33e45b65b2fed4f7829bd4fa75fd1c4e9e397534ea8cef8efeef26b565b7ea7c5170747f87a86de9eafb1451db52fce1b767f059908be7ba05e04bd65d66d142f225b1f92e733636843cc7ef62e85a6ed1d4d5fe8acf585153dc5fbb1a3cf86c34eadb3e6586cd65dfa1a8b8107fb82f95814df2f87eb48bed8cc712b35f8ff8c3e7d73fd2dab60b5c6dfbb25297ed067e3725191c1ddff83d959f43dbf74b9dc73e1cd877e46bcbff65caf49c5af4537576f07dcdd20258976c5fdbb73dfb016b4cbe3be3ba0a74ea67685008f9af9ad49695725256b41676b58fc8376090dd5caeabb15c3194e963a97f3288b7fee6b756fb1acc6a9bfc06e2ec6b38febb6a93fa446874096824651c7fb3d1dabfd2ec5788ed6873a38c2c8bdfa2fb17b45151fd476dc700d7c73159b7ed38661e17ead2cf33dffb69fd07b41771f7d3fa0f8821eca71518ebef08eb17aee641f4b145cafc97b17ef39c5c96c17e60ffbd9fc0f75cca743e9b73f2e3757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c6badb56cb3ca08ee9e96658b229615adcc6f85150547ebe7e63b6be97dbeaf5117896bfc06b9943911eae2e6bc257d0ee8ea9b7249a893ca9759ea2a654e837ded0c9d4fc076c2fdf662cbff65ca740e8863b85f117f9d53dbf74ae04c821ff47d15b0c6e4bb33fa967340f123f642c85fd4b4b6ac94133d446b6157fb889c4721bbb95c85b15c3194e967a97f3288b7fe57183c5718cc6a9b9c0d717631f44377d556f78bd0a823682465f09ea2ed3ba0b67b1daededf883a97c2f797ccf32b3c4eba396fb29fc79af7d56ce7081d0d7e3c47e80eed6cc252d6bc5f28c7cb38fb0de3bb12ddc12fbe2be1eadbcdbd40b724cce379c1f1f4ede23bb6ca5fd49809bd72e03b6acc845cf86e6ff86e9f43df5e73af3993e60ec62048bd7f86df2c5553a6f3521c9740966b028c2ec6724804477e7bfc588c38be832cd714185d1c1fb2fdf679776094e50a81d1c5bba538fe465d18f11bc3789c174607df8aed5cdf6fc5e23dbde6c0c8f4ce263e9b6a018c2ece8bebfbae1e9ecfb7845f57e31275c982b10c1865b956c0e8e2de385ecbd48511af8b64b9d6c0e8e21956b6e33be1b7e7f1deb24bc64cc776c77d51cab2bdf752e99627e3b906fa7630ae614a0bbccf782c2d7abbe5c978ee83be1ddcf74b6981e30c1e4b0b7c36e862dcc34470e473b863f1e0f34b59ee04604c3a62ec9b05631218fffb5e3130f673c498cc82b11f308afd24607470ff35c5d82f0b46bc4f29cb9d0c8c573a62bc220bc62b8151963b05185ddc4b4d80dfba305e058cb2dca9c078b523c6abb260bc1a1865b9d380f11a478c5767c1780d30ca72a703e3b58e18afc982f15a6094e5ce00c6eb1c315e9b05e375c028cb9d098cd73b62bc2e0bc6eb8151963b0b186f70c4787d168c3700a32c773630dee888f1862c186f044659ee1c60bcc911e38d5930de048cb2dcb9c078b323c69bb260bc191865b91260bcc511e3cd5930de028cb25c0760bcd511e32d5930de0a8cb2dc79c0789b23c65bb360bc0d1865b9f381f176478cb765c1783b30ca721700e31d8e186fcf82f10e6094e5be078c773a62bc230bc63b815196fb3e30dee588f1ce2c18ef02c63b2d8cfd1d31de9505637f6094e52e05c6bbe3674c5d4bf7cf82f16ee0b9277e9e94667767c1738f5b9ed477f5eeb6f8ba377e5fa96d3120a87bddef059e81f1f3a4b6c5bd59f00843312c879add173f634ab3815930de073c83e2e74969765f163c8340b3fb2c9add1f3f634ab3415930de0f3c83e3e74969767f163c8341b3fb2d9a3d103f634ab3c159303e003c43e2e74969f640163c43825acd1eb06836347ec6946643b2601c0a3c55f1f3a4341b9a054f156836d4a2d9b0f819539a5565c1380c78aae3e74969362c0b9e6ad06c9845b3e1f133a634abce827138f08c889f27a5d9f02c78468066c32d9a3d183f634ab31159303e083c23e3e74969f660163c2341b3072d9a8d8a9f31a5d9c82c184701cf43f1f3a4341b9505cf43a0d9288b660f3b627c280bc6872d3c717f27fb218baf318eea3e3aa87bdd85a11896c37e12631d318ec982712c30ca72d84fa2c611e3d82c186b8051964b3866ccd44fa2067c8f8bdf77aa5daa09eaaecf38b73c19fb49a0eff18eb41817d45d8bf16e7932f69340df131c69313ea8bb16138067a2032d12e0a32e3cc2500ccb613f89498e182766c13809186539ec2731d911e3a42c182703a32c87fd241e71c438390bc647805196c37e12531c313e9205e3146094e5b09fc4a38e18a764c1f82830ca72d84fe231478c8f66c1f81830ca72d84fe271478c8f65c1f83830ca72d84fe209478c8f67c1f80430ca72d84fe249478c4f64c1f82430ca72d84fe229478c4f66c1f81430ca72d84fe269478c4f65c1f83430ca72d84f62aa23c6a7b3609c0a8cb21cf69378c611e3d42c189f0146590efb493ceb88f1992c189f054659ee61c78c99ae5f9e6de4bea3ae551abbefa8eb92c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3fe7c077027cc85460cc27212f0cc5b0dcc39eb15133224f497c3ca55877f4f53c41dd9fb7f01438aa3bfa7a81a0eec2d0d0189f6b008c0f370046af63ba0f627d1815cf8bf0ff648c3c2f64c1f322f0bce488e7c52c785e029e97e3e749c5d44b59f00843312cf77003607cae01307a1dbd8e4c8c5ec7fcd1d1337a46cfe8198f07634368c33d638388c7b2fa322a9e69f1f3a4347b390b9e69a0992c778f5bc6b2fa322a9ee9f1f3a4349b9605cf74d06c9a4533078c65f565543c33e2e74969363d0b9e19a0d9748b660e18cbeacba87866c6cf93d26c46163c3341b31916cd1c3096d59751f1cc8a9f27a5d9cc2c78668166332d9a39602cab2fa3e2991d3f4f4ab35959f0cc06cd66593473c058565f46c533277e9e9466b3b3e099039acdb668e680b1acbe8c8a676efc3c29cde664c13317349b63d1cc0163597d1915cfbcf879529acdcd82671e6836d7a2192be3c30d80f1b906c0e858c7b2fa322a9ef98e78e665c1331f785e71c4333f0b9e5780e7d5f8795231f54a163cc2500ccb3ddc00189f6b008c5e47af2313a3d7317f74f48c9ed13366c7f87c0360f4dbda33b2323ab8becaf80ecd2b8ddc77d43b348ddd77d43b348dddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97e2d7edf65d97e63e635e071f1cd1b47f52c55eb7d5dafebdb18f5535abd6168f58aa1553194791df47bc3817e05e057d62df3e22f5be60b09981df92e53ed4b2ba8bff878ced043f97fd351dda3dafa371bb9efa8b6beb1fb8e6aeb1bbb6f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7316df986f16d49eb7cbf74fd53aded2f9423d2fe59f07bb9499d822fddb2ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff57e680273078820c3cf3c8782693f1cc24e31949c633888ce756329e2bc9789e24e32927e31947c6338c8ce76e329e1bc8782e27e3e943c633858ca72719cf2c329e87c8785e22e3194cc6733b19cfd5643c4f93f19491f14c20e3194ec6732f19cf4d643c49329ec7c878ba93f15c4cc633868c673619cf45643c43c8785e26e3b9938ca7988ca72d19cfb5643c2f90f15c46c65341c6f30c19cf5c329e49643c0f92f1dc47c6534ac6730b194f27329e2bc8789e20e3e94ac633878ca7868c671a194f15194f7f329e4bc878ae27e3694ac6d39b8c673e19cf23643cbdc8784691f17424e3b99f8ce736329eabc8789e22e3e942c6339e8c673a194f3519cf00329e1bc978fa92f13c4ac6d3838c673419cf85643c0f90f1dc41c6938bef9966c3d3868ca7888ce71a329e67c978a692f17426e39948c633838c670419cf40329e9bc978fa91f13c4ec6d38d8c672c19cf50329ebbc8785e24e36947c6d39e8ce73a329e02029e4470f4182609f8ff6b606b622cab3efb3aba43edffdfd6f626b0cc3b3adfd4b2eeb7c126df927dc7b22ceaf436d425a9f3a5df6d4ae984be92302ffe8a80e31d129eebc878da93f1b423e379918ce72e329ea1643c63c978ba91f13c4ec6d38f8ce766329e81643c23c8786690f14c24e3e94cc633958ce759329e6bc8788ac878da90f1bc46c6730719cf03643c1792f18c26e3e941c6f328194f5f329e1bc9780690f15493f14c27e3194fc6d3858ce729329eabc8786e23e3b99f8ca72319cf28329e5e643c8f90f1cc27e3e94dc6d3948ce77a329e4bc878fa93f15491f14c23e3a921e39943c6d3958ce709329e2bc8783a91f1dc42c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643c1791f1cc26e31943c67331194f77329ec7c87892643c3791f1dc4bc6339c8c6702194f1919cfd3643c5793f1dc4ec633988ce725329e87c8786691f1f424e39942c6d3878ce772329e1bc878ee26e31946c6338e8ca79c8ce749329e2bc9786e25e31944c633928c672619cf64329e79643c95169ed71cf1c8fbeeb26e997f8dc4b783ed50aad6fbaea33abda7d7d54caf57f8c55f219499da3afdabde0fc76585cbfc3e01be9bf31e68f49ea3bac8f62830b60ffa7ecb916f79474bd62df36f3572df6d0ddf6df3c4777bc377fb3cf1ede3dcc7793ef8f671eee33c1f7cfb38f771cee4dbc1b541197e274da602633e0979bc5e70f17d3947f53ce23af1db18f5535abd6f68655e5b1543997741bff71de867bbf69479f1972df38504cc18172541bc71b120fe3a95a976ab15e8bac0d017ebb5d091a651c790858ddc77d431a4b1fb8e3a863476df3ece7d9ce7836f1fe73ecef3c1b78f731fe74cbe17e97c8cd78da5e8433d5f94eb8145e07789ce17c4e857ad6bb15e57a15eb7702c01bb94f94f78aee9f779bfcfc7e5db1fdb7c9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8668e73332ffdc52f023657fdf9a3623117ef121c4fdf51b1d8d87d47c56263f7ede3dcc73993efa50e7c27c0874c99faf82d059ec50e781cd533f56c639951a7d78c3a1543193cc62f7350cf02f02beb96f965c0235325f0b88883ba6c73e49947c633998c672619cf48329e41643cb792f15c49c6f324194f3919cf38329e61643c7793f1dc40c67339194f1f329e29643c3dc9786691f13c44c6f31219cf60329edbc978ae26e3799a8ca78c8c670219cf70329e7bc9786e22e34992f13c46c6d39d8ce762329e31643cb3c9788690f1bc4cc67327194f31194f5b329e6bc9785e20e3b98c8ca7828ce719329eb9643c93c8781e24e3b98f8ca7948c672119cf2d643c9dc878ae20e379828ca72b19cf1c329e1a329e69643c55643cfdc9782e21e3b99e8ca729194f6f329ef9643c8f90f1f422e31945c6d3918ce77e329edbc878ae22e3798a8ca70b19cf78329ee9643cd5643c03c878de27e3b9918ca72f19cfa3643c3dc8784693f15c48c6f30019cf1d643c6dc8788ac878ae21e379968c672a194f67329e89643c33c8784690f10c24e3b9998ca71f19cfe3643cddc878c692f10c25e3b98b8ce745329e76643cedc978ae23e32920e0490447bffb9f80ffbf0f367947fd35b02dd7f9c5606b62f1d154e79781ad50e7651d2dc234a5c3d1eb469d5cbd978fbe92302ffe8a80633909cf75643cedc978da91f1bc48c6731719cf50329eb1643cddc8781e27e3e947c6733319cf40329e11643c33c8782692f17426e3994ac6f32c19cf35643c45643c6dc878ee20e379808ce742329ed1643c3dc8781e25e3e94bc6732319cffb643c03c878aac978a693f18c27e3e942c6f31419cf55643cb791f1dc4fc6d3918c6714194f2f329e47c878e693f1f426e3694ac6733d19cf25643cfdc978aac878a691f1d490f1cc21e3e94ac6f30419cf15643c9dc8786e21e35948c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643cb3c978c690f15c4cc6d39d8ce731329e2419cf4d643cf792f10c27e39940c65346c6f33419cfd5643cb793f10c26e379898ce721329e59643c3dc978a690f1f421e3b99c8ce706329ebbc9788691f18c23e32927e379928ce74a329e5bc9780691f18c24e39949c633998c671e194f658e78d4bbedd2d73a002e9c92905f063c0b1df038aa67297ed7e0db18d7abb45a6168f5bea1553194590afaad70a05f01f89575cbfc0ae07956e76ddf54789684516c0b1df324a0ce3265da0756008f8b7dd2513d53b1bad2a8d3b316dda50cc6ea4a07f5b4ed3b32bf12785ed079614d40b9174818c5b6cc314f02ea2c53a6585d093c2ef61d47f54cc5ea2aa34e2f5874973218abab1cd4d3b6efc8fc2ae07951e7853501e55e246114db0ab73ce509a8b34c99627515f0b8d8771cd53315abab8d3abd68d15dca60acae76504fdbbe23f3ab613b7866cf6c63563c72ff5e581350ee251246b1ad74ca535e9a803acb94a91d5b0d3c2eda7947baa7dab135469d5eb2e82e653056d738a8a76ddf91f93516df2541bc5aacad83166b2d3c6b73ac85f8cb9679690364f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e6266d059f1c8f709853501e55e266114db2ab73ca9f7825e0e8e9c0a8cf924e4d702cf6a07fa38aa67aa0ff93aa34e2f5b749732b87fad73504fdbbe23f3eb603b64c3bca601327b9debc7ac78a6e9bcb026a0dc341246b1ad76cb936ac7a605474e99dab175c0e3a29d7754cf543bb6dea8d3348bee5206f7aff50eea69db77647e3d6c07cfec996dcc8a67bace0b6b02ca4d276114db5aa73c65a9f71ba707474e99dab1f5c0e3a29d77a47baa1ddb60d469ba45772983b1bac1413d6dfb8ecc6f80ed900df39a06c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9df34767c53343e7853501e56690308a6d9d539e2ea9e70e338223a74ccf1d36008f8be7328e744f3d77d868d4698645772983fbd74607f5b4ed3b32bf11b64363675ed300997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1ccd479614d40b999248c625bef9627f5dd8399c19153a67e3b1b816783037d1cd533d56f679351a79916dda50cee5f9b1cd4d3b6efc8fc26d80e9ed933db9815cf2c9d17d604949b45c228b60d6e7952edd8ace0c829533bb609785cb4f38eea996ac7361b759a65d15dca60ac6e76504fdbbe23f39b613b7866cf6c63563cb3755e5813506e3609a3d836bae549b563b38323a74cedd866e071d1ce3baa67aa1ddb62d469b645772983b1bac5413d6dfb8ecc6f81ede0993db38d59f1ccd179614d40b939248c62dbe4982701759629533bb605785cb4f38eea996ac7b61a759a63d15dca60ac6e75504fdbbe23f35b8167aece0b6b02cacd256114db66c73c09a8b34c9962752bf0b8d8771cd53315ab1f18759a6bd15dca60ac7ee0a09eb67d47e63f009e793a2fac0928378f84516c5b1cf324a0ce32658ad50f80c7c5bee3a89ea958dd66d4699e45772983b1bacd413d6dfb8ecc6f039ef93a2fac0928379f84516cd88ecd77c45364f01459b4385ebe9516153adf46ff26e0ff15c0e8aa6d996f30ca3cc6b8d88a72a0595b83a7ada1d9f1f4adb4a884bc9a707b550223c3f66a9b03cdda1b3ced0dcd8ea76fa5456f9d6fa77f717bf5064686edd51e781cb4cfe50983474d998edddb1cebe3a89ea963f7f6c0ae3b1e87a40c1ebbb73ba8a7ed5c42e6b7c376f0cc9ed9c6ac78faebbcb026a05c7f1246b1e139ff8ef879ca13068f9a32b5633b1cebe3a89ea9766c6760d77d07e82e653056773aa86701f89575cbfc4ed80ed930af6980cc5ee7fa312b9e013a2fac0928378084516cdb816757fc3ce50983474d99dab15d8ef57154cf543bb63bb0ebbe0b749732b87fed7650cf02f02beb96f9ddb01db2615ed30099bdcef563563c03755e5813506e2009a3d87602cf9ed879d263be208f9a32b5637b1cebe3a69ee9766c6f60d77d0fe82e6570ffdaeba09e05e057d62df37b613b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563c83745e5813506e1009a3d87603cf87b1f3a49f3b208f9a323d77f8d0b13e6eea997eeeb02fb0ebfe21e82e653056f739a86701f89575cbfc3ed80e9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99b99915cf609d17d604941b4cc228b6bdc0f351fc3ce50983474d999e3b7ce4581f47f54c3d77d81fd875ff0874973218abfb1dd4b300fccaba657e3f6c87fd9ed9335b9815cf109d17d604941b42c228b67dc07320769ef4f353e45153a676ec80637ddcd433dd8e1d0cecba1f00dda50cc6ea4107f52c00bfb26e993f08db211be6350d90d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63ae78fce8aa74ae7853501e5aa4818c5b61f783e8e9da74b69c2e0515381319f84fcc78ef57153cff4738743815df78f41772983fbd72107f52c00bfb26e993f04dba1b133af6980cc3e3672c3ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc0cb1a178aa755e581350ae9a84516c0781e793f879ca13068f9a0a8cf924e43f71ac8fa37aa6faed1c0eecba7f02ba4b19dcbf0e3ba86701f89575cbfc61d80e9ed933db9815cf089d17d604941b41c228b643c0f3a9039e84c1a3a64cedd8a78ef57154cf543bf65960d7fd53d05dca60ac7ee6a09e05e057d62df39f01cf489d17d604941b49c228b6c3c0e32256154f91c123f39f12f8565ad4e87c1bfd8bdbab061819b657510e346b6bf0b435343b9ebe9516e320af26dc5ee38091617bb5cd8166ed0d9ef68666c7d3b7d262bcceb7d3bfb8bdc60323c3f66a9f03cd8e677b783cf7ede319a75ef3e3a779c171d4bce0386a5ee035a7d2dcc1f1a50c8f650130e09484fc67c0f3c3f87952f7b83ecb82e787c0f383f8793a3baa67a95aef8f803daef52aad7e6c68f599a155319441861f3bd0af00fccaba655efc7966cf1cc58ce7b6c29a80729f92308aed07c0e3a2dd5075bf4caf4bd6df2c4cfb4eaaf5ebe2d903de776da6d72b1ce2af10cadc5e525bf6a0662b82ffcb7653f53964d81cbd0fdcd9f60c4ce6c55f5190bbfba099eecba2162e9edd647bdc3f64e1f9363e9e52dccfd1d7414775cfe639da410b4f8c75ef1cf50cf140fc754fb51f9df4ba64fd6a1ffdfc24a79a97e3be27ed4727a3ce8550e6b292dab25f40fb616b2b5cef9b724e6eee9b4d82daf64cb84ab4dd7cbef2adb64bb94fa03cb63915fa17f7cf0aa8abab7631ea1e13b68b66dbed527bf3199fe9bb1874f9845433db730ad4b1d2c25d49c08df198cbfd4cd66d7b465669e8c8a6196eeb4f2c3af6b670f726e066dcaf7b1b3ab26976acfdbabf85bb3f0137e37edddfd0914db363edd7032cdc0308b819f7eb01868e6c9a1d6bbf1e68e11e48c0cdb85f0f347464d3ec58fbf5200bf720026ec6fd7a90a1239b66c7daaf075bb807137033eed7830d1dd9343bd67e3dc4c23d84809b71bf1e121ca9239b66c7daafab2cdc5504dc8cfb7595a1239b66c7daafab2ddcd504dc8cfb75b5a1239b66c7daaf4758b847107033eed7230c1dd9343bd67e3dd2c23d92809b71bfae6bbf7dd6fdbac6c25d43c0cdb85fd7183ab26976acfd7a9c857b1c0137e37e3dced0914db363edd7e32ddce309b819f7ebf1868e6c9ad9f66b47efe59565fb9ee061a7faa4c76b3e9c05cfc7c0e322a61cc541a9a37e2ea9bea9070cad0e1b5ae1381807413f077d6132bedf2ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f333e3370ef1f98a94fb8484516cf84ccac57d7e55f7cbf5ba64fdcdc2d4f9945abf0763f75b565a60f84b0287f82b8432ff794e6dd9ae9aad28387abbe1b8d6b82df7c75e87f4b634e35fe6c55f11d4e700f038783f3fc573d0e03968d102df3b8dc777d930371a9795aaefefb40a6ab7f37ea33ea8e947b1fb3f52d30243d38f1cfb4e04476e4f61c0290979e471f16cd8513d536dc13ea34ea6c6c550e642a8e73e07f52c00bfb26e99df073c3235011e573118183c81451f992ac9782693f18c24e3b9808c671019cf69643cb792f1b422e3b9928ce749329e72329e71643cc3c878ce25e3b99b8ce744329e1bc8782e27e32924e3e943c633858ca72719cf43643cdf27e3194cc6732919cf19643cb793f124c878ae26e3799a8ca78c8c670219cf70329e0e643cf792f19c4cc67313194f73329e2419cf63643cddc9782e26e31943c6731119cf10329eb3c878ee24e32926e3694bc6732d19cf33643c15643c9791f14c22e379908ce77c329efbc8784ac9784e25e3b9858ca71319cf15643c2dc9789e20e3e94ac65343c65345c6730e194f7f329e4bc8784e20e3b99e8ca729194f6f329e47c8787a91f18c22e3e948c6f33d329efbc9784e27e3b98d8ca73519cf55643c07c8789e22e3e942c6339e8ca79a8ce710194f0919cf00329e93c8786e24e36946c6d3978ce751329e1e643ca3c9782e24e379808ce74c329e3bc878da90f11491f15c43c633958ca73319cf44329e11643ce791f10c24e339858ce766329e16643cfdc8781e27e3e946c633968c672819cfd9643c7791f1b423e3694fc6731d194f01014f2238fa5b4c09f8ff41b0c937833e065b13cbfae439b59457c7c5673b1cbdee2696757f6461409d3e84ba2475bef4bb4d299dd05712e6c55f11707c44c2731d194f7b329e76643c7791f19c4dc633948c672c194f37329ec7c978fa91f1b420e3b9998ce714329e81643ce791f18c20e39948c6d3998c672a19cf35643c45643c6dc878ee20e339938ce701329e0bc9784693f1f420e379948ca72f194f33329e1bc9784e22e31940c65342c673888ca79a8c673c194f17329ea7c8780e90f15c45c6d39a8ce736329ed3c978ee27e3f91e194f47329e51643cbdc8781e21e3e94dc6d3948ce77a329e13c8782e21e3e94fc6730e194f15194f0d194f57329e27c8785a92f15c41c6d3898ce716329e53c9784ac978ee23e3399f8ce741329e49643c9791f15490f13c43c6732d194f5b329e62329e3bc978ce22e31942c6731119cf18329e8bc978ba93f13c46c69324e3694ec6731319cfc9643cf792f17420e3194ec633818ca78c8ce769329eabc97812643cb793f19c41c6732919cf60329eef93f13c44c6d3938c670a194f1f329e42329ecbc9786e20e339918ce76e329e73c9788691f18c23e32927e379928ce74a329e56643cb792f19c46c633888ce702329e91643c93c9782ac9789a183cf87ff56ed8019d976f0715c2ffefd69dcbdbe97549197946acee55ec356caabe7b1cd5776f503b25617e0fd457d8f702cf5e473c1f1a3ca6ef22c8578266bb0d9b62dce58871b7c128f3bb8051f4db0d3cbb1df1ec31784cdf4590ef0d9aed346c8a718723c69d06a3ccef0046d16f27f0ec74c4b3cbe0317d1741be3f68b6ddb029c66d8e18b71b8c32bf0d1845bfedc0b3dd11cf0e83c7f45d04f901a0d907864d316e75c4f881c128f35b8151f4fb00783e70c4b3cde0317d17417e2068b6c5b029c6cd8e18b7188c32bf191845bf2dc0b3c511cf5683c7f45d04f941a0d926c3a618373a62dc6430cafc466014fd3601cf26473c9b0d1ed37711e40783661b0c9b625cef887183c128f3eb8151f4db003c1b1cf16c34784cdf45901f029aad336c8a71ad23c67506a3ccaf0546d16f1df0ac73c4b3dee0317d1741be0a345b63d814e36a478c6b0c46995f0d8ca2df1ae059e38867adc163fa2e827c3568b6cab029c6958e1857198c32bf121845bf55c0b3ca11cf6a83c7f45d04f911a0d90ac3a618973b625c6130cafc726014fd5600cf0a473c2b0d1ed37711e4478266cb0c9b625cea887199c128f34b8151f45b063ccb1cf12c37784cdf4590af01cd961836c5b8d811e3128351e61703a3e8b704789638e2596af098be8b203f0e345b64d814e342478c8b0c46995f088ca2df22e059e48867b1c163fa2e82fc78d06c8161538cef3b625c6030cafcfbc028fa2d009e058e78161a3ca6ef22c8df0936e1ed05b6f774be27d8ded5f91e607b47e7bb83ed6d9def06b6b774be2bd8ded4f972b0bda1f35dc0f6bace9781ed359def0cb65775be0fd85ed1f9be609baff349b0cdd3f97e609babf357806d8ece5f09b6d93a7f15d866e9fcd5609ba9f3d7806d86ce5f0bb6e93a7f1dd8a6e9fcf5607b59e76f00db4b3a7f23d85ed4f99bc0f682cedf0cb6e775fe16b03da7f3b782ed599dbf0d6c0febfced60bb47e7ef00db619dbf0b6c9feafcdd60fb4ce7ef05db0f74fe3eb0fd50e7ef07db8f74fe01b0fd58e78782ed273a3f0c6c3fd5f9e160fb99ce3f08b69febfc28b0fd42e71f02db2f757e34d87ea5f363c0f66b9d1f0bb6dfe8fc04b07daef313c1f65b9d9f04b6dfe9fc64b0fd5ee71f01db173a3f056c7fd0f947c1f6479d7f0c6c7fd2f9c7c1f6679d7f026c5feafc9360fb4ae79f02dbd73aff34d8fea2f353c1f6579d7f066c7fd37969d7543bfb779d2f09e26d67bf096aa712f02dfe54997fe87c73a38c2c5b08655aeb0e85ea19877a7749da616997954ddae1f7c026edf0bb609376f81db0493bfc36d8a41d7e0b6cd20ebf09366987df009bb4c3af834ddae1d7c026edf0ab609376f815b025757e3ed8a41d9e07366987e7824ddae1396093767836d8a41d9e0536698767824ddae119609376783ad8a41d9e063669875f069bb4c32f814ddae117c126edf00b609376f879b0493bfc1cd8a41d7e166cd20e3f0c366987ef019bec2fdf804ddae6c36093b6f953b049dbfc19d8a46dfe01d8a46dfe21d8a46dfe11d8a46dfe31d8a46dfe09d8a46dfe29d8a46dfe19d8a46dfe39d8a46dfe05d8a46dfe25d8a46dfe15d8c6eafcafc1266df36fc0266df3e76093b6f9b76093b6f9776093b6f9f76093b6f90bb049dbfc07b049dbfc47b049dbfc27b049dbfc67b049dbfc25d8a46dfe0a6cd2367f0d36699bff02b667745edaea96609367c56a2afd8e138ec3d3047c094b3288b7edc7290979acbb4c95643cb3c8784692f1bc45c6730119cf20329ed3c8785a91f12c20e31947c6339f8c671919cf52329ef7c978ce25e3d944c6b3918ce744329ebd643c7bc8782e27e32924e39941c6f306198fbcf7c9c233988ce752329e33c87812643c73c9789690f12c26e379978ca70319cf06329ef5643c2793f1ec26e3d945c6d39c8ce71b329e69643c1793f1bc46c6731119cf10329eb3c8788ac978da92f15490f15c46c6339b8c671119cf42329eb7c978ce27e35947c6b3968ca7948ce754329e9d643c3bc8783a91f1b424e379898ca7868ce715329e2a329e73c878fa93f15c42c67302194f53329ede643cf790f1cc24e379938ca72319cff7c878d690f1ac26e3f92b19cfe9643cdbc978b691f1b426e33940c6339e8c671e194f3519cf7b643c87c8784ac8780690f19c44c6d38c8ce73019cf74329ed7c9785691f1ac24e339938ce703329ead643c6dc8788ac878e690f18c20e379878ce73c329e81643ca790f1b420e379998ce755329e15643ccbc978ce26e3d942c6b3998ca71d194f7b329e7d643c1f92f11410f0248023009bfcbf29d8e43b3c87c0f6b5ce1f009b7cc36701d8bed2f967c0f694c5d6c4c2270c53c126efca7e0d36b93ff334d8e49d89afc026e70de25fcd4fef70347f135846fc34b5f0a3bfaf2c5c92c7ed2dcb248378b737fa4a06f66fde15188cc79be743329e7d643cedc978da91f16c26e3d942c6733619cf72329e15643caf92f1bc4cc6d3828ce714329e81643ce791f1bc43c633828c670e194f11194f1b329ead643c1f90f19c49c6b3928c671519cfeb643cd3c9780e93f13423e339898c6700194f0919cf21329ef7c878aac978e691f18c27e33940c6d39a8c671b19cf76329ed3c978fe4ac6b39a8c670d19cff7c8783a92f1bc49c633938ce71e329ede643c4dc9784e20e3b9848ca73f19cf39643c55643caf90f1d490f1bc44c6d3928ca71319cf0e329e9d643ca792f19492f1ac25e35947c6733e19cfdb643c0bc9781691f1cc26e3b98c8ca7828ca72d194f3119cf59643c43c8782e22e3798d8ce762329e69643cdf90f13427e3d945c6b39b8ce764329ef5643c1bc8783a90f1bc4bc6b3988c670919cf5c329e0419cf19643c9792f10c26e3f93e19cf1b643c33c8780ac9782e27e3d943c6b3978ce744329e8d643c9bc878ce25e3799f8c672919cf32329ef9643ce3c8781690f1b422e3398d8c671019cf05643c6f91f18c24e39945c65349c6d3c4c273c8118f7c2b46d62df3871ab9ef3d86ef3d79e27b97e17b579ef8de61f8de9127beb719beb7e589efad86efad79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efa586efa579e27bb1e17b719ef85e68f85e9827be99afbf553f5ce9abbc4fff26e0ff15c0b8c011e3218351e61700a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba93dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba95dc0d3db114fd4bd92de04be9516f2eeb3bcf39780ffe378ebae62aab7c128f3b698da013cfd1df144dde3e94fe05b6921df0a936fd224e0ff383ea3ab98ea6f30cabc2da670fcdc018e78a2ee4d0d20f0adb4906fedca372f13f07f1cbfc9554c0d301865de1653387edc40473c51f7d40612f8565ac8b360f9467b02fe3f08185dc5d4408351e66d3185e3dd0c72c413752f7010816fa5c5609d973e5609f8ff6060741553830c4699b7c5d446e019ec8827ea1ee66002df4a8b213a2fef7024e0ff4380d1554c0d361865de1653eb816788239ea87baf43087c2b2daa745edee94fc0ffab80d1554c0d311865de16536b81a7ca114fd43de32a02df4a8b6a9d976fce25e0ff38fefb10478c5506a3cc0f0146b1ad069e6a473c51f7baab097c2b2de4dbfeabf46f02fe8fe3b1ba8aa96a8351e66d3185e3418f70c413758f7e04816fa5c5489d97316112f0ff91c0e82aa646188c326f8b291cbf72a4239ea8670b23097c2b2de4db5ccbf46f02fe5f038cae626aa4c128f3b6985a0a3c358e78161b3c8b2d5a1c2fdf4a0be9cbbd44ff26e0ffe380d1554cd5188c326f8ba9c5c033ce114fd4b39c7104be9516f26ded45fa3701ff1f0f8cae626a9cc128f3b6985a083ce31df1443d831a9f03df51cf5372e13bead9402e7c47dde7ce85efa87bb6b9f01d75ff3117bea3eea5e5c277d47da15cf88ebac7910bdf51d7ebb9f01d75ed990bdf51d751b9f01d754d900bdf51e7b7b9f01d75ae960bdf51e71dbe3df7ed79dcbe8fe7b943beb6e7c7f3187a3c8f25fedac05f1be4cab73f96f86b835cf9ced76b03df9ee7be3d97ebaf8220fa7a6cb923df4b0ddf328fcf59963af2bdd8f02df3f8cc60b123df0b0ddf328ff7bf173af25d64f896f98539f0ddd6f0dd3687bedb1bbedb5b7cbbd8de89e0c8eb6f61c02909798c81450e781cd5b354ad77895ed7b731aed776dfc6dc5f8aa1cc12d0cf75db21ebced476b48ccf7769027cc837be944d9ec5be07366943df059b3c637f076cd2cebf0d3679bef316d8e4f9cf9b601ba9f387c126cf61b1ffbb3c4bdf01b62a9dc77ed743747e1bd8a45f12f6f795be655bc126fd03b19fa9f4f1dc0c36e9a78bfd1ba5aff546b0497f79ec5727ef3cac079bbcb782fdb9e4dda3b5603ba0f3d88f48bee9b21a6c53757e15d8fea2f32bc1f6a4cedf03b62f75fe1bb0fd59e71782ed099d5f04b63fe9fc12b03daef36f80ed8f3aff3ad81ed3f9d7c0f6a8cee37b617fd0f90fc1f685cee3fb4853747e0fd87eaff3f81ecc233abf0b6cbfd3f957c13659e75f01db249d9f0fb6dfeafc3cb07daef373c13651e7e780ed373a3f1b6c13747e16d87eadf333c13656e76780ed573a3f1d6c63747e1ad846ebfccb60fba5cebf04b65fe8fc5fc1f690ce2f065b139d5f0a36197f11fb7c14eafc72b0c9b8f4d89747be953f1e6c2d747e1cd85aea7c0dd8e43b6b23c126632b8f005b42e7abc1d646e7abc026e73a43c02663890c069b9c970c025b3b9d1f08363987180036191bb23fd8e47b9ebdc17692ce57824dbe535f01b65374fe10d864fcae0560936fc01d009b8c6bfc34d8e4dbcf53c176a6ceff056c32a6c993603b5be7bf04db393aff67b0c9f7309f005b89ceff096c1d74fe71b09da7f37f049b8c37f518d82ed0f947c126e3f0fe016cf2ede42fc076a1ce4f01db453aff7bb0c9b81c8f804dc6dafc1dd83aeafc64b0c937ad2781ed329dff2dd864ecbccfc126dfeb9d08361923ed3760ebacf313c056a6f3bf065b179d1f0bb6729dff15d8baeafc18b075d3f9d160ebaef3bf045b0f9dff05d87aeabcb4336a7f56fbf9413d9f0ce23dcffe383872ca749e2d0cc813e7796b31f0a0affdb1d7bd2c758e2cfb7d13bd5e89a1fde07b5fecbed3e7e71fe97515eaf5ee337c17429996ba7150cbc931bfa95eee80b11cde139275cb329783fd4363dded747d3f7254df7d069370a30e52a68d6652c7c68d3adf12968991ad4ced03126b0168885312f2c2e046abb2523cefad0bcf47c0b33f769ef4b5af8b98c07d2bee6b5ff39ea8196bc550661fe8f7a103fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac780eea3c3e579672074918c5b61f785cdce7c7e7b0b27ef55ce7fd736bfdee8fddef91cff79ae9f5961a752e84327f86674e8b75be08fe2fdb2d6a5b3a784e98715b8abf22a80f3e0b3ae88867bfc1b3dfa285e44b62f35d36cc8dc665a5aadf8a7ac67ec0d0f5a0455357fbeb7ebdae024353dc5f3f3678f0d96811f07ea27f13b09e4fa00e0ef6f18c7121fe705fda0f36c97f0c8c2eb6331e4ba43d90e7e1f86c5acaec329e8bc7bfedcb4a5db61b7ba14ec9e0e8f82e8432fba0eddbaff3d837e420e8f633cbff65caf49c5af45375de1d7f9d53db77177026c10ffade09ac31f93ee27d94029dc48fd80b21ff53e8cf21e5440fd15ad871ec6f643797fbd858ae18caecb1d43f19c45bffdd06cf6e83596d938f21ce7e06c77f576dd29e088d2e078da4cc7ed0e880239efd068f70883f5546b67f73a38c2c5b08657e0b6d94aa8bb4f3524fecdb82c70057c731f125eb9679dbb9f147c068d651c547e7536a79f7c7cedbb0fa7ffd03da8bb8fb7ffd0362a800380263fda5b07ee16a1e441f5ba4ccff308ea32eae31705b9a7aa2ce52e67f413bf4fd92743e9b73fde375dd1675aebfc7014f2238f2da5b4d998eef788cd9eb80c7513d4b6dc7ae0f8d3a1543990ba19e0ece6332be57bb1b7cbbd8e6a8859c43ed33b42884320525e95f693ba274c46bd58f72529732ebf960a9a52e52a645496d5d5a823d4e2697db6d27d449ad77bfa5ae52a64d49ad2ec53a9f80ed84f74dceb6fc5fa64ced018e6bb33dfe3aa7b6ef36e04c821ff4fd01b0c6e4fb88ef6ac8f9bef8117b21e4cf2aa92d2be5440fd15ad8d53e22effc21bbb9dc3e63b96228b3c352ff64106ffdb71b3cdb0d66b54dda97d4e6258e5cb69b3b22342a058da40cde3f96633bbe77673beeef77c41d75dcdf0f8c66bb89e72e2ed90e186ce63d54dbf9a094c1733229d3b124fdabdad984a56cb3e0c87bc32eee63e23ba801d42330ea2a13c680836bc372bc7692764afc7402fb7e9d179d3b19da154299ae25e95f87e7ddd67b97e6f51d5e5308b7b96fe1bb1fbd4a6ab9711cc2fdfab7086c9fea5f47d769e5b67b86c261bb67982ca965c76585ebb0a52ee6357293e0e87beadf1a65f1be5ba6e5ccbc39a6a3d2f753a39ccd0f5ef3c4f6ae46e7d252646a12d8ef177c6cb01704478f5f29fb01c69c791fa593b11ebc8f726b49fa57da24b3acdaf69f9f54ab8f6c47d10edb138cc98f8131a9f3a5df6dea6cabbfcc8b3fc5f8895107376d57fa7da56cee031f001e176dbba336ba148fb1f17d9fa26795edf8ffb1a1550e9fd75a8ff9e633f796463e1edf65d5b6fb4f362df659785c3d4789d2629fc5777c5a741b663b7ed8b4c865df87282d3eb4f88e518b1178df3393167b2d3c2eee4565d262afc5777c5a742fcdf45c03b5d863e17175ef214a0bf1972df38704cc2d8d7c3cbecbab6cf7c96c5aecb6f0b8ba6e8ed262b7c5777c5a74ee86f7e83269b1cbc213fffdb9cc5aecb2f88e4f8b1e3df11e5e262d765a785c3dd38dd262a7c5778c7131dc762fc7a6c50e0bcf8e1c6bb1c3e23bc6f3c36eb67b6d362db65b781cdc77cda8c5768bef18b5188af75d3369b1cdc2b32dc75a6cb3f88e4f8baaaeb67bc2362d3eb0f0b8ba271ca5c50716dff16931b487f2bdb50e5a6cb5f06ccdb1165b2dbe63bc864ac5c5963a68b1c5c2b325c75a6cb1f88e4f8bead4b9d6e63a68b1d9c2b339c75a6cb6f88e4f8bd2d43175531db4d864e1d994632d36597cc71817a9ebc98d75d062a38567638eb5d868f11de3712415171beaa0c5060bcf861c6bb1c1e23b3e2d46a4ee3fadaf8316eb2d3ceb73acc57a8bef18efb9a4e2625d1db45867e15997632dd6597cc7a74597d431756d1db4586be1599b632dd65a7cc7a7c5f0d433b13575d0628d85674d8eb55863f11de37967aabd585d072d565b7856e7588bd516df319e77a6ee5facaa8316ab2c3cab72acc52a8bef18dbced479e7ca3a68b1d2c2b332c75aacb4f88ef1bc33a5c58a3a68b1c2c2b322c75aacb0f88ef1bc33751c595e072d965b7896e7588be516df31c645aaed5c56072d96597896e5588b6516df31ded74ab59d4beba0c5520b8fabf11aa2b4586af11de3f548ea1edf923a68b1c4c2b324c75a2cb1f88ef15951ea1c7c711db4586ce1599c632d1683ef03b1fb4ef7e7161fd217eb32438b4228f36d49fa57fa6245e928ebc07e65589745b1d725ddaf6c61445d16415da44c6187dabab40c9c8cf753eea8aea99859007552ebfdc4525729d3aa43ad2e099d4fc036390cba9d61f9bf4c05c67c12f2a29faaf37bf1d73915abef026712fca0ef77803526df9dd177814ee247ec85903fbd436d5929277a88d6c2aef691f7751ed9cde5161bcb154399f72df54f06f1d6ff3d83e73d83596d936288338923376d579ae9fd088d2e038da40cf6d9fbc4118fd9875038c49f2a23dbbfb95106fb504a99f3a08dc27ea552cf447074bf49476d5967649775cbbcf82b06db016034eba8e2631ff4fd94b122641c0965937121bac07aba1b3655d71e8eea2abe64dd32df0318659c8aeeb9672cab2b63378351f1f472a0198ebd2153a6e3452fe0e9e980c7513d53c7a10aa34e3d8c3a1543197cb7b1c2413d0bc0afac5be62bc0b78b6d8e5ac831f962438b42ac37b46799749475a8f8ed6ea94b1fc77591754bbbd42707be2b0ddf5d0ddf89e0c8ed1c0499f7af4a60eeed8059adb76ffceb2dc5f3368929f1d315ead40f3488ab4eb82e39cfeb67685b08f9fe709e27e5a4ac1cbf845dc5b26c4b643797eb652c570c65fa58ea9f0ce2ad7f5f83a7afc1acb6c90d706ee7607f48c5401f8343e6bb82767d23b4eb03da49193cfe7573a45d6f8347e6bb018f9ce354804dce15843f01ffef92036eb3ddabb0708b0dc789eb6661ec1a3f63ea5ca79bc128f35d81516cbd81a7d29166e6b6bed8d0078fcbcd8d32b26c219479088e8d094b59b5df5d58505bafa6da1edbbb63ba4d6fee402f1ca731007d0243c300f4927a3673c0d33aa81dab71e2a49a09431f1c7ec7f0f4a347412b3430f1b7c0528d2660c37c538b2d088e1c92b2106c32246533b0353164c1a130a5bc0c69e7422ed443d65d6870b60496387de3709e32650a9d16c0e3229455e8c8909e3a74ee99306ad2708c8f6606677d6247fdaf69867251eb72b51dcc7d2209f3660c163af2df14ea9b8479f1a7b68d0cad3a6ee8b087fb4d7870f298e163274d44a1cc1d1bf305c1911bc0fc8d12dcd54e87018015c6c6a199512f6c30e47fb2615ac7cf598e63e69ada04e04fa6d6a05b2b07baa9f5cbd8b7c3868e1e7ddbe4aad1a3865d3379ecb049a36ac6e2d66c692817b5a5e5ffcdc1666be2b1ac9ab0d9c2655b586cb60947196e09363972b5029bf0b4065b53c84b7973cb3809d70b60fdb24ba9ff29719ae98ab7086a43400ec7aa5d55fbaf3a95539f9055a7426a6863b539d5d0c5ea8ea11a9a587dc54e0d3dac861a56430b9f11a4870e5643059f1da48702565fbb2809d243fb9e17d40eddaba6c3c0f9bd203d34afba4d7351903eed5243eb760cd243e7aa5b979d82f467ded4bbf5eaf45ddd1650a7bcea124f9d7eaad34e7579a16e5fa85b59ea944e9d2eab534175faa62e47fa6aadfb85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bb82f4f0ce7707e9e1d7d5f0cff706e9a1a1ef0bd2c346df1fa487947e20480f373d34480f453d2c480f533d3c480f61fd60901ede7a54901e26f7e1203dd4ae1a82776c901e0e5b0d93ad86cf56c3fcaa2181d590c26aa861352cb11ac2580d81ac86467e3c480fb9ac866c7e2a480ffb3c354ccf84e9d9303d17a6e7c3f442985e0cd2c383ab61c3a705e961c6d5f0e33383f470e5b383f4f0e66ad873351cba1a265d0d9fae865557c3bcabe1dfd5b0f06f86e9ad30bd1da41f49a84731ea1185bafdaf1e83a95bd48b82f4adf32541fa11b77ae4afba40a82e21aa8bccaa20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a7f90be2d7e30483f2a55b7c3d5a301158feaf6fd6761fa41987e18a61f85e9c761fa49987e1aa69f85e9e7417a586335dcb11a2e590dadac8661564336aba19cd550d06ad8e82f82f4d0d36ae8ea3f05e921b1bf0cd35761fa3a480faffdd730fd2d4cdf84e9ef61fa4798fe19a67f05b54369636371866e61f4554a3074d2a4e163c64d2a9954533266f2e849a3c68d7eac64caa849234b6a1e193e61c4e89a29b8f00ff5c2320e78bf0913863e56326a6cf5f0474b6a264f2aa91951525533796cf51107ea7fea85ce3adae3d0eaea6867fffe5d48ff6f3d9db6d26d9f8cb07e7de6bab5695a0f414ea8cf42dd9ad6af4213f4514a2e67ef4c9feb964c1c5d33a9a4b4646cf8373cb8d64c195edda904ff37311479e2a4928993864e9854326242cd9892ce9d70bd4fb7ae4725fea3b51b985667d44f9c16fa5b4af50ab19de7d64381cfcfad1fe9dfbf0be9bfd5d369eac09b6d0d9bd767a14b4aea47585e1229cbc4c95593260c1d36297ae19edf65e1bef5a9e62df5ace67fd5c759d30ef558a84387fa11f6ad8fb35159380bfe3f244cae11d44d0600", + "bytecode": "0x1f8b08000000000000ffed9d079c1545beef7b8621e87146cc028651519078e630648483398b2092c330e41c86282819441104910c43ce8860d8e866379936e8aebb77f7eedebcf7ed0b9ff73ef7bef7ee7d6fefeb3aa7fe6f7e14d5e39cb16bfc8d547f3e35a7fa37d55ddffa757575a8eeaebc203bfd290c793ade200c2d830b27f97f5aff263fdf5412e3ba922e39f3ea09677e3de16c504f380bea0967c37ac2d9a89e7036ae279c4dea09e725f584f3d27ac299a8279c97d513cec27ac259544f382faf279c4deb09e715f584f3ca7ac279553de1bcba9e705e534f38afad279cd7d513ceebeb0967b37ac2d9bc9e70b6a8279c37d413ce1beb09e74df584f3e67ac2595c4f386fa9279cb7d613cedb62e46c0b9c72cffe76fd7b87fe6da57f5bebdf3bf56f1bfddb5697b140cfb70b43fb3074084347e37fca1875e33e15864ec6ff4ac3d0390c5dc2d055ffaf58ffaf5b18ba87a147187a86a15718ee0a43ef30f4d17ef40dc3dd61b8270cf786e1be30dc1f8607c2f060181e0ac3c36178240c8f86e1b1303c1e8627c2d02f0c4f86a17f180684e1a9300c0cc3d3611864b00c0ec390300c0dc3b0300c0fc388308c0cc3a8308c0e435918c684a13c0c63c3302e0ce3c330210c13c330290c93c330250c53c3302d0cd3c330230c33c3302b0cb3c330270c1561981b867961986f78b6200c0bc3b0280ccf189c8bc3b0240ccf86e1b9302c0dc3b2302c0fc38a30ac0cc3aa30ac0ec39a30ac0dc3f36158178617c2f06218d687e1a5306c08c3c630bc1c864d61d81c8657c2b0250caf86616b18b685617b18768461a766911d6157187687614f18f686a1320cfbc2b03f0c07c270300c87c270380c47c270340cc7c2703c0c27c270320ca7c2703a0caf85e14c185e0fc3d9309c0bc31b6178330c6f85e1ed307c250c5f0dc3d7c2f0f5307c230cdf0cc33b61f85618be1d86ef84e1bb61f85e18be1f861f84e1dd30fc300c3f0ac38fc3f09330fcd4f0fcbd30bc1f860fc2f0a1d63ed2bf3fd3bf3fd7bfbfd0bfbfd4bf1febdf4ff4efaff4efaff5efa7faf737faf7b7faf7aff4efeff4efeff5ef5febdf3fe8df3feadfbfd1bf7fab7fff4efffebdfefd07fdfb8ffaf79ff4afeac75bde221b6f12544de920a636a7745c99ba8f2f669afd84aa0faa81fe9ffc166bbd40cfcb6f9ed61beaf98686de48cf3732d6d344cf3731f4223d5f64e84df57c5343bf52cf5f69e857ebf9ab0dfd163d7f0be809fdbf6cc1b23f4a6ba0a53cd0a4fee583d6506b0d406b24ab03adb1d61a8226dbb711689768ad3168976aad096809ad5d02da655abb14b442ad25402bd2da65a05daeb542d09a6aad08b42bb4763968576aad29685769ed0ad0aed6da95a05da3b5ab40bb566b5783769dd6ae01ed7aad5d0b5a33ad5d075a73ad5d0f9adec58266a0dda0b5e6a0dda8b516a0dda4b51b40bb596b378256acb59b40bb456b378376abd68a41bb4d6bb780d6526bb78226e70ab7694dd53369fb32cb683d1fb4db65ff06ed0ed9b7416b25fb3568ad659f06ed4ec85bb436b28f83d6566b52c7d5ffbae8783a88ab7d4b95abf5768d7bbde19ad57abbc7bfdea46a2f7b04555ea7219faee0554f1d8ff1798612cc3b4f07c947f402883f0069259df821ed94b0abb6a79b8ef7ac66b92ec6724590a69ba5fce920def2773778ba1bcc6a9bf4028ef8eb6ca7a4afb3359e72aeb30321ad59f7e498f965acb30f0387833a5beaeb6c8da79ceb6c39a435eb9e9cbf7d19ebec60e0705067bbb9a9b3a9a4afb3d97b264160af7b722df165acb3e38123fe3adbd9d7d99a4f39d7d9e720ad59f7e4baf6cb58672b8023fe3adbb59b3f37a8f194739d5d0f69cdba27f758be8c7576397038a8b3e5be9dadf194739ddd0969cdba27f7fbbe8c75762370c45f67bb3baab39d7c9d0db2fd5f4160af7b72eff9cb5867f70047fc75b6dcdf9fadf994739d7d1bd29a754ffa41be8c75f6a48eab7e868f743fc30da0fd4c6b3782f673addd04da2fb4763368bf84fe42d13e96be44d03ed1daada0fd4a6bb781f66ba3ef55699f6aed76d07ea3b53b40fbadd65a81f6575a6b0ddaefb4762768bfd75a1bd0fe5a6b6d41fb83d6da81f647adb507ed6fb4d601b4bfd55a47d0fe4e6b49d0fe5e6b25a0fd83d652a0fda3d63a81f64f5a2b05ed4f5aebac35d54f297d5fef6aad0970a583f8ea68023c9029cf984f43bca35b9e6411f0605e25f1e7d54995fdbc87ad3ea3ec25c0937250f604e451139e14f0748a9f27f38e5f69fcebcd6ce3a4e16902f24a42b93a3b28571ee425eb9679c9af0834dca73b5b18633fcf082fbcf2202f59b7cc770146d1b08d913657f61f758cf967e075b02f65ce33243f797759384a409734d7b7a862fb2f5a2b84ff637bdbc9d01cd5cb4cbd90bc64dd325f0a8c529e4e75cf98aa2963ca6074d546e4415eb26e9f77d576907807e0e9e688c76cd324ef6e7590771723ef12236f6c3b65aaeed8d605981d5c6f957c11d75b78fec070bd75455e555af3ba49dae15cafb73a1bcb315e6f35caabe270b03f64ea40378343e64bc0bbee11de7503ef24cdede09d8373cf8c775d0d1e994f018fb463a5c0d3a18e793a10e48de7b0b2ddf05a0acf035c6daf0e06a3ccdbb65717604c59181d9c13a6aa3b469600a368783f2ae9c8b3a8ed9a24c9dbc57525be4b21e7e6e6b54d01a4f93ff9d95fd556b6cf73ca96c27367996a7acd1bff764a2571ffa8098fe37da8c4517d4ce2fd9bbf04f1d635b35d32db9ba87b3caedaf2a4c123f3929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c523fd09f8dc96a4eb44c2683effe6ea3e7fe65b28b22efdabfa75de817e9df8fb2d5249ecfb93e7205a19652e80341fe555a5fdae8eab670ea49f0a9fb5329fbf72d96787cf63a6615ef2c367ad705b323cef541c5bded9efd2b8e86fbb3cc87e53c77cf6b393c55317cf3fa3a77986a7f81cf89d068faaa7ff915fc5e6a2ef2fd7be48f44ae271f6ed1505f6ba1eff76499dd7679d1f9cdf7ee071c6d5f33bd2564b7f793723ef0248f37b788e4a9ead92718692c672f8dc8fac5b9669057a7763dd4df5b2c2d1d0587f292c2b69fe086dea4aa8ab0edaca54aecfae63bf79fcc7e16c3f7e32079e0ec0e3a29d7174be91c47d20ee7e7cf3f934db798ca4c167fb1c3c5759edf34e929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c563f6b5e2fbb525248ca2397ef621d39fd15aaf4bd6affa7566e757e5ebba1f4efa9c5a1b65c67747cfe557a59da7e385c185cf3b446d4b57dfa788da96921f7e7ba603f0b8e8d7cd83bc64dd1d2d5e48bc38b6bcb3fdf8f17b5cd58f9f347c2db178ea6a7fc53e56f414f7d794c1837da351dff6e968688ef6f16aeb85e487fb5247d0248eef47bbd8ce782c319feb91fcb0fffa25ed6dd3c0d5b64f255db61bf8dd94747061fdc6efa96c86b66f8b8ee3331cf8ecc841cbff65aaae9f5afc5365ee157f9933dbf72ee04c433e98776f608d29ef12cc3b4f07c947f402881fc8af4a2be9c40ff15ad8d53e22df80417673b994b15c11a4e969297f3a88b7fcbd0c9e5e06b3da26dba09e1d84e3bfab36a9678447adc0234983e741ae9ec933db48f3f9467c6eaf919106cf5924cd4968a354596ccf8fda9e3974751c8b7ae6d0766edc0118cd329acf795eeccf697d03da8bb89fd3fa06d4217c4e2b30d6df1ad62f5c8d82e8638ba4f9b6b17ef39c5c96c1e7c024cdf7a0bdf8975a9c937f51d757b673725c2eaaec8a19bf83968e9119eb04b2e07982a479dfd866dd23b8bb5896fd286259f1cafc56586170a17f6ebeb396dde77b1965917add13ca22693e31ce01e33f6fc99e03bafaa61c9e7ba8f576b49455d2fc16f6b5dfc1399e6c27dc6fff6cf9bf4cd59d03e2788e7de22f7312f719d9be7d2c79f705d698f22ec175c939605fc3830288ff2768d3259da415af855ded23721e85ece672dd8ce58a204d6f4bf9d341bce5ef63f0f43198d536f903d4b33fc339a0abb6ba778447adc1234983f7146ddf01b5ddeba8ab7345f3fbc245c185f709f038e9e6bcc9fe9e90795fcd768ed0dae0c773847f83763661496bde2f94e3659ccf0de3bb12a590ef7f58f24dc7ec6757f02d0df3785ef045e6ede03be1997744f0bb82c280531ae2f8ed70592e1f185d7c6f3d119cff7de0cf62c46fb0cb720d80d1c536ccf5fbc4a5c028cb1500a38bf7bff01bf93561ec048cb82f0aa38bef92d6f67b8e78dddd081899deabc2fbc78d81d1c5b1abb6efd3e031b709fcba1a3b24990363476094e52e014617f7aff07ca3268c78ee22cb5d0a8c2eee33e73a060b7e1f1aefff08a38b73c05caf51f05e952c771930f670c4d83d07c61ec088f71c84d1c5f56402f2ad09634f60445e6174d0079061ec990323de2b97e52e07c6bb1c31f6ca81f12e6094e59a02a38bfbf909c8b7268cbd815196bb02181d5ceb67187be7c088d7c4b2dc95c09876c4d82707c63430ca725701a38bebf684c1f0598c7d8151f4ab81f16e478c7d7360bc1b1865b96b80f11e478c77e7c0780f30ca72d702e3bd8e18efc981f15e6094e5ae03c6fb1c31de9b03e37dc028cb5d0f8cf73b62bc2f07c6fb8151966b068c0f3862bc3f07c6078051966b0e8c0f3a627c2007c6078151966b018c0f39627c3007c687805196bb01181f76c4f8500e8c0f03a32c7723303ee288f1e11c181f014659ee26607cd411e32339303e0a8cb2dccdc0f89823c64773607c0c1865b962607cdc11e36339303e0e8cb2dc2dc0f88423c6c773607c021865b95b81b19f23c6277260ec078cb2dc6dc0f8a423c67e39303e098cfd2c8cfd1d313e9903637f6094e5ee04c601f13366be43d33f07c601c0f354fc3c19cf06e4c0f3945b9ecc379c0658f27a3afebc32db626050f3b23f0d3c83e2e7c96c8ba773e0118622580e3d1b1c3f63c6b34139300e069e21f1f3643c1b9c03cf10f06cb0c5b3a1f133663c1b9203e350e019163f4fc6b3a139f00c03cf865a3c1b1e3f63c6b36139300e079e11f1f3643c1b9e03cf08f06cb8c5b391f133663c1b9103e348e019153f4fc6b39139f08c02cf465a3c1b1d3f63c6b35139308e069eb2f879329e8dce81a70c3c1b6df16c4cfc8c19cfca72601c033ce5f1f3643c1b93034f397836c6e2d9d8f819339e95e7c0381678c6c5cf93f16c6c0e3ce3c0b3b116cfc63b621c9703e3780b4fdcdf171d67c96ba2a3b24f086a5e76612882e590719223c68939304e0246590efbd7273b629c9403e3646094e5b07f7d8a23c6c939304e0146590efbd7a73a629c9203e3546094e5b07f7d9a23c6a939304e0346590efbd7a73b629c9603e37460445e619ce188717a0e8c33804b96c3fef5998e1867e4c03813186539ec5f9fe58871660e8cb3805196c3fef5d98e1867e5c0381b186539ec5f9fe38871760e8c73805196c3fef50a478c737260ac0046590efbd7e73a62acc881712e30ca72d8bf3ecf11e3dc1c18e701a32c87fdebf31d31cecb81713e30ca72d8bfbec011e3fc1c181700a32c87fdeb0b1d312ec881712130ca72d8bfbec811e3c21c181701a32c87fdebcf38625c9403e333c028cb61fffa62478ccfe4c0b818186539ec5f5fe28871710e8c4b805196c36bae671d312ec981f159605ce2192f0a46e4298e8f278965c7bc9e2328fb73169ebcc04dd931afa504655faa7feb1be3b3f580717c3d60f43e7a46cff8e563f4fbb5f79189d1fbe87df48c9ed1337ac68b9db13eb4e19eb15ed4c7546d1915cfb2f879329e2dcd8167197826cb3de59631555b46c5b33c7e9e8c67cb72e0590e9e2db378e68031555b46c5b3227e9e8c67cb73e059019e2db778e68031555b46c5b3327e9e8c672b72e059099eadb078e68031555b46c5b32a7e9e8c672b73e059059eadb478e68031555b46c5b33a7e9e8c67ab72e0590d9eadb278e68031555b46c5b3267e9e8c67ab73e059039eadb678e68031555b46c5b3367e9e8c676b72e0590b9eadb178e68031555b46c5f37cfc3c19cfd6e6c0f33c78b6d6e2192be3f87ac0f86c3d60ac0f3e7a46cfc8c4e8f76bef2313a3f7d1fbe8193da367acbf8ccfd50346bfad3d232be3baf81953b932ae73ec99a37266c69f7a41af2bc66f22a494572f1a5ead35bc2a82342f807f2f3af02f0ff29575cbbce4972b734b02664779a7645ce4b5467ecf1a7ea869bdfe6d08fa78f0f4251d97b1e724fd73a04b9a597aa00f19d352261c93717dfce52da96edf96fc90672e194f67329e19643cabc9782691f1ac20e31943c6b3948c673819cfd3643c4f90f1b422e3b9878ca73d194f03329e0e643ca5643c7791f13c44c633998c6726194f3919cf3c329e11643cadc9780691f12c26e3e947c6f33019cfbd643cbdc978ba91f1b421e3e944c6338b8c673e19cf14329e95643c63c9789691f18c24e35943c633988ce749329e47c878ee23e3694bc6d39d8ca70f194f8a8c6736194f3b329ea9643c0bc878c691f18c22e36949c633848ca73f19cfa3643cf793f1a4c9787a90f12c24e32921e39943c6d3958c671a19cf2a329e3bc8782690f18c26e35942c6733b19cf50329e01643ccbc9781e23e379808ca72f194f4f329e45643c49329e0a329e2e643cd3c9782692f19491f10c23e31948c6f33819cf3a329e07c978ee26e3e945c6f30c194f1e014f22b8f09dd404fc7f1d68f9c6b28dc330ac45d5ff37683d1f96d9a8e30d2cebde00da4b3abed1b22cfab401ca92d6f1e4e79b323e615e699897fc0a81632309cf33643cbdc878ee26e379908c671d19cfe3643c03c9788691f19491f14c24e3994ec6d3858ca7828c2749c6b3888ca727194f5f329e07c8781e23e3594ec633808c672819cfed643c4bc8784693f14c20e3b9838c671519cf34329eae643c73c8784ac8781692f1f420e34993f1dc4fc6f328194f7f329e21643c2dc9784691f18c23e35940c633958ca71d19cf6c329e14194f1f329eee643c6dc978ee23e379848ce749329ec1643c6bc8784692f12c23e3194bc6b3928c670a19cf7c329e59643c9dc878da90f17423e3e94dc6732f19cfc3643cfdc8781693f10c22e3694dc633828c671e194f3919cf4c329ec9643c0f91f1dc45c6534ac6d3818ca701194f7b329e7bc8785a91f13c41c6f33419cf70329ea5643c63c8785690f14c22e3594dc633838ca73319cf5c329e8e161e07e33b6678e4fd3c59b7ccaf23c9dbc176c88c6bf9b2a3326dd2eb6aa8d72bfc925f01a4f9b071f6b76990ad0fa20bd77a1dc7ba21de6c028f36392a8b6c8f3c63fb38ce3b85ef8d06c01018fe04161e17efdb3a2ae779f530eef155371b5e99dbae08d2bc0cfe6d76e09fad6ecbbce4972b734b0266ac17c541bcf5e295f8cbf4ffc76d155f5f31fcc572bdaae331d6cba45ac716bdae8690dfab90ef361dcf8b315fb5aead7a5d32ceac706c035dd2fc33b4cbc8ac26697ff19b66db753c1d1f73661c6c1c47573cc1290df1edc0b3d5018fa37266b6cd0ea34ceb8c3215419a2d50ce1d0eca9907f9caba657e07f0c8d411785cd4839a6cf3a8b18719783a93f1cc20e3594dc633898c670519cf18329ea5643cc3c9789e26e379828ca71519cf3d643cedc9781a90f17420e32925e3b98b8ce721329ec9643c33c978cac978e691f18c20e3694dc633888c673119cf16329e7e643c0f93f1dc4bc6d39b8ca71b194f1b329e4e643cb3c878e693f14c21e35949c633968c671919cf48329e35643c83c9789e24e379848ce73e329eb6643cddc978fa90f1a4c8786693f1b423e3994ac6b3808c671c19cf28329e96643c43c878fa93f13c4ac6733f194f9a8ca70719cf42329e12329e39643c5dc978a691f1ac22e3b9838c670219cf68329e25643c43c9780690f12c27e3d94cc6f31819cf03643c7dc9787a92f12c22e34992f15490f17421e3994ec633918ca78c8c671819cf40329ec7c9781e24e3b99b8ca71719cf33643c79043c51630fcbff378326efd4e178c43b757c2b68f9963ce459f81da015e8b8ac43bdca39bec585eb469f5cbd478879a5615ef2c3b1877792f03c43c6d38b8ce76e329e07c9781e27e31948c6338c8ca78c8c672219cf74329e2e643c15643c49329e45643c3dc978fa92f13c40c6f31819cf66329ee5643c03c8788692f12c21e3194dc633818ce70e329e55643cd3c878ba92f1cc21e32921e35948c6d3838c274dc6733f19cfa3643cfdc9788690f1b424e31945c6338e8c670119cf54329e76643cb3c97852643c7dc878ba93f1b425e3b98f8ce711329e27c9780693f1ac21e31949c6b38c8c672c19cf4a329e29643cf3c9786691f17422e36943c6d38d8ca73719cfbd643c0f93f1f423e3d942c6b3988c6710194f6b329e11643cf3c878cac9786692f14c26e379888ce72e329e52329e0e643c0dc878da93f1dc43c6d38a8ce709329ea7c9788693f12c25e31943c6b3828c671219cf6a329e19643c9dc978e692f174ac1b9e52f52e1e8ef7295c38a521be0378b638f0c7513993f81e669c63692aaf76195e6d36bc2a8234dbc1bf5d0efccb837c65dd322ff97966cf1cc5ac78e4d970dbfbc14b481845dbe294a734998032cb545dfbb80b785c1c3f1cf99e69c7761b655a62f15dd2605dddeda09cb67d47e6775bf22e0ee2f5624f0dbcd863e1d953c75e487eb9326faf87ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e0781f7d9fbec7d4e7ebec9fbace3de67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e473133f8ac7896eab8b02620dd521246d176b8e5c9bc6fb434387fca33e6d310df033cbb1cf8e3a89c9967c8f71a655a1a5ce8bba4c1fd6baf8372daf61d99df0bdb2117e6ddf590d9fb5c3b66c5b34cc797eadf04a45b46c228da2eb73c99766c5970fe545d3bb617785cb4f38eca9969c72a8d322db3f82e6970ffaa74504edbbe23f395b01d2a3db367b6302b9ee53a2eac0948b79c8451b43d4e795299f71b9707e74fd5b56395c0e3a29d77e47ba61ddb679469b9c577498375759f8372daf61d9997fc7265de5d0f99bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866eff3c5e3b3e2916f260b6b02d2ad2061146daf539e4e997e8715c1f9539e319f86f83ee0a98c9d27dbefe0c0f74cbfc37ea34c2b2cbe4b1adcbff63b28a76ddf91f9fdb01dbeecccbbeb21b3af1b75c3eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c73143343dd503c2b755c5813906e2509a368956e7932df3d58199c3fe519f36988ef079e7d0efc7154cecc733b078c32adb4f82e6970ff3ae0a09cb67d47e60fc076f0cc9ed9c6ac7856e9b8b02620dd2a1246d1f6b9e5c9b463ab82f3a7eadab103c0e3a29d7754ce4c3b76d028d32a8bef9206ebea4107e5b4ed3b327f10b68367f6cc3666c5b35ac7853501e95693308ab6df2d4fa61d5b1d9c3f55d78e1d041e17edbca37266dab1434699565b7c973458570f3928a76ddf91f943b01d3cb367b6312b9e353a2eac0948b7868451b4036e7932edd89ae0fca9ba76ec10f0b868e71d9533d38e1d36cab4c6e2bba4c1ba7ad841396dfb8ecc1f86ede0993db38d59f1f4d771614d40bafe248ca2e1f9cf91f8794a13068f9aaa6bc78e38f6c7513933edd8d1c0eefb11f05dd2605d3deaa09c7990afac5be68fc276c88579773d64f63ed78e59f10cd471614d40ba81248ca21d069e63f1f394260c1e3555d78e1d73ec8fa37266dab1e381ddf763e0bba4c1fdebb88372e641beb26e993f0edb2117e6ddf590d9fb5c3b66c53348c7853501e90691308a7614784ec4ce93fdbe31f2a8a9ba76ec84637fdc9433db8e9d0cecbe9f00df250dee5f271d94330ff29575cbfc49d80e9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99b99915cf101d17d604a41b42c228da71e039153b4fb6df0179d4545dbfc329c7feb82967b6dfe17460f7fd14f82e69b0ae9e7650ce3cc857d62df3a7613b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563cc3745c5813906e1809a3682781e7b5f8794a13068f9aaaeb7778cdb13f8eca99e9773813d87d7f0d7c97345857cf3828671ee42beb96f933b01d3cb367b6312b9e113a2eac094837828451b4d3c0f37aec3cd9fe53e4515375edd8eb8efd7153ce6c3b7636b0fbfe3af82e69b0ae9e7550ce3cc857d62df367613be4c2bcbb1e327b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccdee78bc767c5334ac7853501e94691308a760678cec5ced329993078d4545dbfc339c7feb82967b6dfe18dc0eefb39f05dd2e0fef5868372e641beb26e997f03b6c3979d79773d64f675a36e987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e6266a81b8aa74cc7853501e9ca4818453b0b3c6fc6cf539a3078d454dd733b6f3af6c7513933cfedbc15d87d7f137c9734b87fbde5a09c7990afac5be6df82ede0993db38d59f194ebb8b026205d3909a3686fb8e549250c1e3555d78ebd053c5f899f27d3aebe9503cf5780e7edf8794a1c9533a9d6fb55608f6bbdcaabaf195ebd657855046990e16b0efccb837c65dd322ff97966cf1cc58c6da1b02620dd9b248ca2bd0d3c2eda0d55f6367a5db2fe8661e8d7b42adf73f1e75b8ad72c0df57a8543f22b8034e9e655699fd26c85f07fd96eaa3c670dcdd1b76f4a6cef4bc8bce45718d4d93544b5d734e8858be7fc733dee9fb5f0fc253e9e24eee798978b6f2be5facec5190b4f8c652f897adfc4c577ec54d9dbea75c9fad53e3ab1a953cf4b71df93f6a3ad51e602487303b41f53a1fdb0b515aef7cdbcc0be6fe60755ed9970156bddbc37f117ad4bba73901edb9cfefa17f7cffe505657ed62d43509b68b66dbedd27bf3fe98997711f8728ed433db751cfa38d0c23d90801beb635dee67b26edb3d8481868f6c9ee1b63e67f17190857b100137e37e3dc8f091cdb3cfdaaf8758b887107033eed7430c1fd93cfbacfd7a98857b180137e37e3dccf091cdb3cfdaaf4758b847107033eed7230c1fd93cfbacfd7a94857b140137e37e3dcaf091cdb3cfdaafcb2cdc6504dc8cfb7599e1239b679fb55f975bb8cb09b819f7eb9af69332edd78eee7f67fa49d133355577cff09c537fb2dfabcfe5f993d781c7459d72540f928eeeb966fa49cdf107ce195ee1f8038eefcb56fb5d22c9cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f33bedf8bfd2b92ee0d1246d11c3f9b9fe9cf68a7d725eb57cffeceb8c265bea924f67bca73c9264701a4f9d3f55569e76836ec5fc47ed13386e6725b9ae34fcbbce45708e5c1faefea5deda8baf58625efe2d8f24e95bbf13895bc3c5cc72541d5767ecd280f7a7a3af6fccff734cff0f4b4e3bc737d5f02791cf4c596382a67a62d386594c9f4b808d2b484729e7250ce3cc857d62df3a78047a67ce0715507038327b0f823d35c329ece643c93c8788693f1dc42c6f30419cf35643cf790f15c42c6b3988ca703194f7b329e99643ce5643c83c8786e20e379988ca729194f6f329e02329ef9643c9dc878da90f1d4c53d805c78a690f18c24e3b98d8ce749329e3bc978ae23e3b98f8c2741c6d3968ca73b19cf6c329e71643c43c8786e22e379948ce74a329e34194f23329e85643c25643cd3c878ee20e3194dc673968ce776329e01643ccdc8781e20e32924e3e949c65341c6d3858c672219cf30329e62329ec7c978ae26e3b99b8ca70919cf33643c1dc9786690f18c21e3799a8ca70519cf43643cadc8782e27e3b98b8ca70119cf3c329e52329ec9643c23c8785a93f1dc4ac6d38f8ce75a329e7bc9782e25e3e946c6338b8c672c19cf60329e1bc9781e21e3b9828ca70f194f43329e05643c29329e76643c53c9784691f1b424e3e94fc6733d19cffd643c9791f1f420e39943c6d3958c670219cf50329e9bc9781e23e3b98a8ca72f194f63329e45643c49329ee9643c65643c03c9789a93f13c48c65344c6d38b8c278f8027115cf82d9d04fcff75d0e49b2ff8bdb07ccbfaa49f51d2abe3d0cc1617ae3bdfb2eed31606f4e9249425ade3c9cf379df79d9b3cbd5e9997fc0a81e334094f2f329e22329e07c9789a93f10c24e32923e3994ec69324e35944c6d3988ca72f19cf55643c8f91f1dc4cc633948c6702194f57329e39643c3dc8782e23e3b99f8ce77a329efe643c2dc9784691f14c25e36947c69322e35940c6d3908ca70f19cf15643c8f90f1dc48c633988c672c19cf2c329e6e643c9792f1dc4bc6732d194f3f329e5bc9785a93f18c20e3994cc6534ac6338f8ca70119cf5d643c9793f1b422e379888ca70519cfd3643c63c8786690f17424e379868ca70919cfdd643c5793f13c4ec6534cc6338c8c6722194f17329e0a329e9e643c85643c0f90f13423e31940c6733b19cf59329ed1643c7790f14c23e32921e35948c6d3888c274dc6732519cfa3643c3791f10c21e31947c6339b8ca73b194f5b329e0419cf7d643cd791f1dc49c6f32419cf6d643c23c978a690f19c21e36943c6d3898c673e194f01194f6f329ea6643c0f93f1dc40c633888ca79c8c6726194f7b329e0e643c8bc9782e21e3b9878ce71a329e27c8786e21e3194ec633898ca73319cf5c329e7c8307ffafde3592ebb353fab700febf583f8cd254af4bd2c83b89eaded2094353e53deea8bc2782aa290df3c7a1bcc27e02784e38e23969f0987917427c207876ccd014e351478cc70c46993f0a8ce2df31e039e688e7b8c163e65d08f141e0d91143538c871d311e311865fe30308a7f4780e788239ea3068f997721c4878067870c4d311e74c478c86094f983c028fe1d029e438e780e1b3c66de85101f069e1d3034c5b8df11e3018351e6f703a3f87700780e38e23968f0987917427c0478b6cfd01463a523c67d06a3cc5702a3f8b70f78f639e2d96ff0987917427c1478b6d7d014e31e478c7b0d4699df038c953abe1778f63ae2a93478ccbc0b215e069eed3634c5b8cb11e36e8351e67701a3f8b71b78763be2d963f098791742bc1c3cdb69688a718723c69d06a3ccef0046f16f27f0ec74c4b3cbe031f32e84783fd084b72b68db75bc0b68db74bc33685b75bc14b45775bc13685b743c05da2b3a5e02da66f103b44d3ade11b49775bc03681b75bc1b681b74bc3b682fe9780fd0d6eb784fd05ed4f15ea0bda0e37781b64ec77b83f6bc8ef7016dad8ea7415ba3e37d415bade37783b64ac7ef016da58edf0bda0a1dbf0fb4e53a7e3f68cb74fc01d096eaf883a03da7e30f81f6ac8e3f0cda121d7f04b4f13afe28684fe9f863a0bda9e38f83f6968e3f01dadb3afe24685fd1f101a07d55c79f06ed6b3a3e18b4afebf850d0bea1e3c341fba68e8f04ed1d1d1f0ddab7747c0c68dfd6f1b1a07d47c7c781f65d1d9f00daf7747c2268dfd7f149a0fd40c72783f6ae8e4f01ed873a3e15b41fe9f834d07eace3d341fb898ecf00eda73a3e13b4f7747c1668efebf86cd03ed0f139a07da8e315a07da4e37341fb998ecf03ede73a3e1fb45fe8f802d07ea9e30b41fb58c71781f6898e3f03daaf747c3168bfd6711cf7ee373a5e1cc4dbbe7f1a544dc590b7e4a7d2fc56c71b196964d90248d350df1c55f73b8a82aaf65f8e074a93f67f3b68d2fe6f034ddaffada049fbff2a68d2fe6f014ddaff574093f67f3368d2fe6f024ddaff974193f67f2368d2fe6f004ddaff974093f67f3d68d2febf089ab4ff2f8026edff3ad0a4fd7f1eb4b48eaf054ddaff35a049fbbf1a3469ff578126edff4ad0a4fd5f019ab4ffcb4193f67f1968d2fe2f054ddaffe74093f6ff59d0a4fd5f029ab4ffe34193f6ff29d0a4fd7f133469ffdf024df6b54f419363c2dba0c931e12ba0c931e1aba0c931e16ba0c931e1eba0c931e11ba0c931e19ba08dd6f177409363c2b7409363c2b7419363c277409363c277419363c2f7409363c2f7419363c20f409363c2bba0c931e187a0c931e147a04dd7f11f8326c7849f8026c7849f8226c784f7409363c2fba0c931e103d0e498f02168724cf808343926fc0c343926fc1c343926fc02343926fc123439267c0c9a1c133e014d8e09728c68029adcaf5653f2734e4541d5940f7909533a88f79883531ae2cf40d9655a43c6730b19cf66329e6bc8782e21e3694fc6534ec6b3948c671019cf8b643c3790f17c4ac6b38d8ca72919cf21329e83643c05643c6dc878ce90f1ec24e3798b8c671519cf6d643c7792f15c47c6f332194f828ca72d19cf10329e75643c3791f1bc4ac6732519cf01329efd643c8dc878de26e3b9838c670519cf59329edbc9783690f13423e32924e31946c6b3968ca7988ce715329eabc978f691f15492f13421e33945c673928c671919cf7a329e16643cadc8782e27e3d94ec6d3808c6704194f6b329e5bc9785693f16c22e3b9968c672f19cf1e329e4bc9784e90f11c27e379818ce746329ead643c5790f13424e36947c6338a8c6725194f7f329e8d643cd793f1ec26e3d945c6731919cf31329ea3643ccf93f1dc4cc6b3858ce72a329ec6643c65643ccbc9780692f1bc44c6d39c8ce757643c3bc8788ac8788e90f11c26e3c923e0490047009afcbf0168f2beee59d0e4bdde33a0c93bbf3b419377821783b6d0a2e55bf884e113d0e45d918f4193fb0f8b409367f47e099a1ca7257f35bfa0c585fcf9967236b0f02fb294f363cbb2b8bd65997410eff6c6bcd281fddb1c7906e317cd73988ce708194f1119cf0e329e5f91f13427e379898c672019cf72329e32329ec6643c5791f16c21e3b9998ce779329ea3643cc7c8782e23e3d945c6b39b8ce77a329e8d643cfdc9785692f18c22e36947c6d3908ce70a329ead643c3792f1bc40c6739c8ce70419cfa5643c7bc878f692f15c4bc6b3898c673519cfad643cadc9784690f13420e3d94ec67339194f2b329e16643cebc9789691f19c24e33945c6d3848ca7928c671f19cfd5643caf90f11493f1ac25e31946c65348c6d38c8c670319cfed643c67c9785690f1dc41c6f336194f23329efd643c07c878ae24e379958ce726329e75643c43c878da92f124c8785e26e3b98e8ce74e329edbc8785691f1bc45c6b3938ce70c194f1b329e02329e83643c87c8789a92f16c23e3f9948ce706329e17c9780691f12c25e32927e3694fc6730919cf35643c9bc9786e21e35943c6936fe139eb8847fab265dd327ff64b9ef77123efe31749de478dbc8f5e24791f36f23e7c91e47dd0c8fbe04592f77e23effd1749de9546de951749de7b8cbcf75c2479ef32f2de7591e4cd7cdea2be47d15fc74fe9df04fc1fbfe379c611e3598351e6cf00a368380e477f473c51e73cfd09f2565e0cd47179d72601ff1f088caeea547f8351e66d750abf8b3dd0114fd4b9da4082bc951772cf48de0d4fc0ff0701a3ab3a35d06094795b9d3a0a3c831cf1449d630e22c85b79217de4f2eda004fc1fc7857555a706198c326fab53f81db4218e78a2ce8d8710e4adbc90673aa5ef2301ff1f068caeead4108351e66d75ea20f00c73c413754e3f8c206fe585bc1325cf5625e0ff38ce8dab3a35cc6094795b9dda0f3c231cf1541a3c95162fbea8bc9517f24d817dfa3701ffc7efe0bbaa53230c4699b7d5a94ae019e58827ea1a6a1441deca8b321d97777b13f0ff32607455a746198c326fab5338ce4d99239ea86bbf3282bc9517d26726dfa249c0ffcb81d1559d2a331865de56a7f0bbfce58e78a2ae59cbeb20efa8ebafbac83bea5aa22ef28e3a2fae8bbca3cef1ea22efa8f395bac8bbd2c8bbb20ef38e3a8ed445de516da2dfbffdfe1d77de5fe4b1a4d2c8bbb20ef3fe22f7ef2fb24dfd22db167fdee2dbb5bacadb9fb7709fb7fc25bebc93787dda24c6f5e27d811dfa17efed6c074deeb56c034dee976d054dee79be0a9adcb7de029af43dbc029af41fbd0d9af40162dfa4bcb371123479260dfbc4648c89e3a0c95814d817f30b1d3f0ada021dc73e80f93a7e18b49feb38de7bfe998e1f046d9e8e1f00ed231ddf0fda5c1ddf07da873a5e095a858ee33d9e393abe07b40f741cef2dbcafe3bb409bade36f81f69e8e7f0ada2c1d2f07eda7166da68e6f066d868e6f02ed273afe32683fd6f18da04dd7f10da0fd48c75f026d9a8eaf07ed873afe22685375fc05d0a6e8f83ad0ded5f1e741fb818eaf056db28eaf01edfb3abe1ab4493abe0ab4efe9f84ad026eaf80ad026e8f872d0beabe3cb40fb8e8e2f056d9c8eff0ab46feb781968f93a3e0ab4063a3e0234790f671868f26dd521a0c9fbe58340936fd00f04ad898ef7074d9e95c6316ae47b8e38468dbcb38963d4c877af178126dfdac0b167643c0e1ca346be01f60bd0e43d9605a0c9b75be78376a58eff1c34f9c6fdcf4093efd8cc034d9ec5fe0834f91ee25cd0e41dcc0f4193ef46578026dff298035a731dff0034f9a6d7fba0c97b20b341936fb1be079abc6f3d0b34f966fd4f412bd6f199a0dda2e33340bb55c77f02da6d3afe63d05aeaf874d0e4db1c3f024dbeff300d34f9a6da0f416bade3534193774ba78026efc3bd0b5a5b1dff0168f2dde3c9a0c9bb08df07ad838e4f02ada38e7f0fb4a48e4f04ad44c7278096d2f1ef82d649c7bf035aa98e8f03adb38e7f5bffaafd4fed97afebf97410dff994caef5c70fe9467cca7212e0cc813e7395611f0605eafc55ef654529553daaf7cbd5ea92faf41dea762cf3b99c9fbb45e57815eef2923ef0248f33fafafda3627b4d6402f77c6580eaf8165ddb24c3bd04f1aeb6eaacb7bda51794f194cc28d3e489a7fd74cea58b64737a08e9e7d4ba97d40ea5a001ee29486b830b8f12a95c4f3ed9af09c069ef8f7936489ab3a81fb569c6d88ed1e9059d78a20cd29f0efa403ff705f9775cbbce4e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1487f02f68f4bbad7491845c3beaed3f1f324b1cf55d6affa755e847e1dd7fd7b0df57adb1b652e8034ef37ab4abb51c70be1ffb2dda2b6a5837ec26ab7a5e45708e5390d3c2efa8bf3202f59f76b162f245e1c5bdea972371ea792ea3913d5c76e3ee3f6bac55357fb2bf6dda2a7b8bf9e3378b06fb41078dfd0bf0958cf1b500607fb78b5f542f2c37de935d0247e0e185d6c673c96487bd04ecf63dfb4a439aabd957ef1f8b77d2ae9b2dd3801654a0717d6ef0248730adabed7741c9f0d791d7c7bc7f27f99aaeba716ff54998fc55fe6243e032fdbf79825ef23c01a53dee73d7f9fa783e4237a01c4bfd9ac2aada4133fc46b6157fb883c3b8bece672e78ce58a20cd714bf9d341bce53f66f01c3398d536390bf5ec1d38febb6a938e4778d40e3c9234781ee4ead879c6e0110ec90fdbd146461a59b600d2bc0b6d942a8bb4f352cea86380ebe398acdb761c338f0b094b1955fd98714515efc5fefcd727d05ec4fdfcd7275087f039adc0587f7b58bf70350aa28f2d92e637c671d4c535066e4bd34ff459d2fc1edaa16bf4c3b8b99ceb7f51d76d51e7fac71df02482f3afbdd554ddf11d8f31271cf0382a67d276ec3a6994a908d2b484723a388fa9f63dc26390b78b6d8e5ec839d429c38b0248f3df8cb623ca47bc563d5d27654959cf07db5bca2269fed568a78e3a6072b9dd8e4099d47a5fb39455d2fc3bb47fff17cee7653be171f8b2e617fe5fa6eada03f14f95f950fc654ee2bb9fb27d0f59f23e00ac31e57dde7ba772be2ff9885e00f144f3aab4924efc10af855ded23f26e1bb29bcb9d32962b8234872de54f07f196ff90c173c860cebc87d4bc2a2ef5c865bb7938c2a3f6e091a4c1fbc7726cc7f71b6df7b55c7d7b35eabc19bfbd2a1ab6cfd780a72e9efdb65db398f7506de783ed0d7e3c1f6cae999b06e7bf8f836dce8b6e9ff92fc1f75c03284760943530d81cf95c8a3e9bf700db826efa2cffb35d33b4049febe2feb4709bd702783d22dce67106af47ee046e55ef653be17d44d1ded4bf8ecec94bf17a4b8e31e63939de47eb08ecb8ac70bd61298b782069f3e1fff2bfbf04f6eb93cf5ace8c9f359651febe69a4b3e5d304968ded5d8d9264d2e43f637062db2ce96cbeca7e80754ed665ee2b785f54d2f436da2433addaf6139b56f923db51bcc3f604eba4abfb4851dfea96fc14a3dc03c2ef9bbbb88f92ebfb53786fc545dbeea88d4ee2bd8bf8beffd07d8ced9ecbeb865745c185f7335cb6e951e723a72c79c7e7456aacadbfdfe6455df6f77fd63dcd26463c9ebcbb94dbda399b17272c3c2eeebf54e7c5094bde317a31de764fc4e6c5710b8fabebed282f8e5bf28ecf8baed6fb55362f8e59785c5d77457921f9e5ca7c8280b989118f27efd231785faa3a2f8e5a78e2bf2755bd17472d79c7e7454997eafa3fd18b23161e57fd98515e1cb1e41d9f17ddbadbee5fd8bc386ce1395cc75e1cb6e41d63bd1867bbbf64f3e29085c7c1bdc66abd3864c93bc6f3c32e78afb13a2f0e5a780ed6b117072d79c7e84599ed3ea8cd8b03161e57f741a3bc3860c93b3e2fc6745679efaf8117fb2d3cfbebd88bfd96bce3f3a2ac9bca7b5f0dbcd867e1d957c75eecb3e41de33554a65e54d6c08b4a0b4f651d7b5169c93b3e2fc666ceb5f6d6c08bbd169ebd75ecc55e4bdef17991cc1c53f7d4c08b3d169e3d75ecc51e4bde31d68bccf5e4ee1a78b1dbc2b3bb8ebdd86dc93bc6e348a65eecaa8117bb2c3cbbead88b5d96bce3f3627ce6fed3ce1a78b1d3c2b3b38ebdd869c93bc67b2e997ab1a3065eecb0f0eca8632f7658f28ecf8b4e9963eaf61a78b1ddc2b3bd8ebdd86ec93b3e2fc665fac4b6d5c08b6d169e6d75ecc5364bde319e7766da8bad35f062ab85676b1d7bb1d592778ce79d99fb17afd6c08b572d3cafd6b117af5af28eb1edcc9c776ea981175b2c3c5bead88b2d96bc633cefcc78f14a0dbc78c5c2f34a1d7bf18a25ef18cf3b33c791cd35f062b38567731d7bb1d992778cf522d3766eaa81179b2c3c9bead88b4d96bc63bcaf95693b5fae81172f5b785eae632f5eb6e41de3f548e61edfc61a78b1d1c2b3b18ebdd868c93bc6bea2cc39f8861a78b1c1c2b3a18ebdd80079bb7a5f47f29067b1da185e14409aff6c3c8b15e5a3ac039f2bc3b2bc147b59b2cf95ad8f28cb4b501649f33f8c67f9d63b607254d64c9d7911caa4d67bce525649f3bfe099e17f8367cf659bbc01be5dd2e2c2ffcb54dd3348e29f2af3baf8cb9ca9abcf03671af2c1bcd7026b4c799760def26cbae4237a01c49bb4a84a2be9c40ff15ad8d53ef2828e23bbb9dc0663b92248f382a5fce920def2af3378d619cc99f71ea09e493d72d37665995e88f0a80d782469f099bd371cf19c33788443f2c3e70c1b196964d902487385f6509edb95e720a59c51cf483a68cbaa7d4652f2c3678b5f0346b38caa7ef483673f3b6abd4350a5950837aca7d4d054593b3b2aabe425eb96f9cec028635294d63d63aaa68c9d0c46c5d3d5816738ce864cd51d2fba024f17073c8eca99390e7533cad4d9285311a4c1771bbb3928671ee42beb96f96e90b78b6d8e5ec831f90ec38b0248d311dab3ea7c9475a8fa5b6a294b4fc76591754bbbd4b30ef2ee6ee49d32f24e04e76fe720a87effea0ecc3d1c30abf5f68a7fbd99fdeb2ebd2ea953924f0acad41b3c88ab4c98b79ce7493ea21740fc5e38cf9374e2871cbf845dd565d996c86e2ed7d558ae08d2f4b4943f1dc45bfe5e064f2f83596d93ee706ee7607fc8d4819e0687cca7c0bb5e11def504ef240d1eff4a1d79d7c3e0e961e4ad78e41ca71b6872ae20fc09f87fb20eb8cd76af9b855bb4eec0683bd7e9143f63b5e73a9d8051b41ec0d3dd9167e6b6bec3f0078fcb8d8c34b26c01a41902c7c68425addaeffe19ca256317c638ce4fa64d6fe4c02f1c5731007f02c3c300fc92723674c073695035b6e29c8a19b3cb268ceb3f2edbf52868050626fee6598a910f1ac61b58b420387f08c902d06408c986a0e51bb6e0d095925e86b4736117fa21eb2e30389b004b9c79e3f09b325557751a038f8baaacaace657a5dbaea0c9a3da9621cd68f8606676dea8efa5f836ad245adcbd57630f78934cc9b75b0c051fe0da0bc699897fcd4b629d4f19965e553face9e3077dab8e91573d02873c7c6785e70fe06307fa30c77b5d36105c00263e3d0d028173618f23fd93097c6cf598a63dc9ade04909f4c97826f9738f04dad5fc6aa2d2f9b3ab5dfdc31532795df3f777a79c5a419d3716b36319c8bdad2f2ff46a0d99a784cab266cb670d9c616cd36e1a8c04d409323d725a009cfa5a03580b8a437b78c93eada12d62fbb94fa9f32a7a12e78e3a0aa0ac8e158b5ab6aff55a7729707d953a12b82ece654430daba185d550c26ae8603554b01ad1527dd542dd7556674f6a685f3594af1aba570dd55b1c6487e2bd35a81a6a574def02e7ed41f6544b0d9ddb3ac80e8dab6e57aad7d5d5a7ddd4a734d429bbba15a04e73d5659dba0451a79dea7453ddb250b7afd4699c3a4556a77fea944d5d82a84b0f75a9a82e9dfa68affb86e1ee30dc13867bc3705f18ee0fc3036178300c0f85e1e1303c128647c3f058181e0fc31361e817862783ec50d203c2f054901d6afae9203b0cf5e0203b44f5d0203b7cf5f0203bb4f5c8203becf5e8203b24f698203ba4f9d8203b4ceef8203bd4eec4203b5cefe4203b34f0d4203bbcf0f4203b94f1cc203b1cb21a3a590dbdac866456c337aba19ed550d16a08e9854176686a35ecf4e2302c09c3b361782ec80edbbd2cc80ef3ad86ff5e1964870b57c388abe1c5555782ea42515d0beab6bdeabe52b796559796bae5adba6255d7b4eaaa578f2ea84739d4a32dea511ff5e8937a144c3d1aa71e15548f4eaa4749d5a3b5ea5163f5e87565907d347f7f907d7543bdcaa25eed51af3aa957bf8e06d95703d5eb9dea7549f5faaf7a1dfa7490bd9dad5ead575d9cea16b7ba95ad6eebabdbee6a68f9b7c3f095307c350c5f0bc3d7c3f08d307c330cef84e15b4176f8e1ef04d9218cd510c8df0fb2432babfaa8866cfe51901d0afa27417688e9f782ecd0d51f04d921b13f0ab2436dab21b8d510debf0cc3c74176d86f35fcf9af83ec90f6bf09c36fc3f05761f85d187e1f86bf0ec31fc2f0c730fc4d18fe360c7f1786bf0fc33f84e11fc3f04f61f8535035f4353616bfd333b7e8f9b28a8a71d366561457cc289e36776ac5a499531716cf9f5431b178c6bc71b3c74f9d311f175eaf9b2719b7bbefecd9650b8b274d1f3b6e41f18cb915c533c6178f993177fad8f30ed427f442375c9863d9d8b1d1997d3dff73907eab9699bea7979311d11faabe6c1fd6c6908f6bb3d0ffae658166eaa397dc3e19903dd72d9e3375464571b2787af8373cb8ce983f6e6c8762fcdf9cd0e43915c5732aca6657148f9f3d635a7149075cef078d6b51883f35760353704dedccf9573d9672adaad89166b570e007cd6a47fa71b3cf41fa692d33fdafb529e1bfd466a166cd6b47785bf3485be6cc1d5331bbacbc227ae1d69f67e10ecd6b51ccbb6a59cc3fd726b3ff5e9b859ab6a81d618716b5c86c700e9905ff0f4017f891c0fa0400", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d77701cc795c667911856581024981324db1423b8586430813953a6242b072650a44512140925cbb2244b72ce395b4e6739e77c9673ce39e7ecba2adf3f57bef255b9ae7bb69ff1a139b3c6aee6816fb06faa1eb6e76defbc5f7ff3a667b67b7690098acb9f8d655cb9d6d8638273177a7fc0bde61fddd29ee0b6f29c9c999470d6a484b336259c7529e1ac4f0967434a3827a58473724a38a724c899013e2edea929e3cda68cf782201d79db9812ce5c4a389b52c2392d259ccd29e19c9e12ce1929e16c4909e7cc9470ce4a09e7ec9470ce4909e7dc9470ce4b09e7fc94702e4809e7c294702e4a09e7e29470b6a684f3c294705e9420e70ae0a431f2c7bad7c7b9d725eef562f7bad4bd2e73afcb5d1bebdcbadde64a63ab8cb579efadb6ccc6ec6079c17bafc358a7b12e63ddeebd56f75e8fb15e637dc6fa8dad31b6d6d83a63eb8d6d709a6c34b6c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd825c61e6f6cbfb14b8d5d66ec72634f307685c772a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b8d9d3076d2d8296343c64e1bbbc5d81963678d0d1bbbd5d86d9e66b71bbbc3d89dc69ee471de65ecc9c6ee36f61463f718bbd7d87dc69e6aec7e630f187bd0d8d38c3dddd8338c3dd3d8b38c3ddbd8738c3dd7d8f38c3ddfd80b8cbdd0d88b8cbdd8d84b8cbdd4d8cb8cbddcd82b8cbdd2d8ab1c0b1d08af36f61a63af35f63a63af37f690b137187ba3b137197bb3b1b718fb0f636f35f6b0b1b7197bbbb177187ba7b177197bb7b1f7187bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fb4f639f34f688b14f19fbb4b1cf18fbacb1cf19fbbcb12f18fba2b12f19fbb2b1af18fbaaa7f9d78c7dddd8378c7dd3f9bee55ebfedead231ff1df7fa5df7fa3df7fa7df7fa03affe0fbdf51f79eb3f76af3f71af3f75af3f73af3f77afbf70afbf74afbf72afbf76afbf71afbf75afbf73afbf77af7f70af7f74af7f72af765e6dc5cc62797230b20c0409f5499d837d765c9dc4f6e7edec9c50ad7b8f5e5b9dbfceadd36bc6f9ebdd7abde76f70eb0dde7626bbf5c99e3fe7d6739e7f9a5b9fe6f9a7bbf5e99ebfc5adb778fe0bddfa85e0cfbaf78a0d2bbe585fad7365c047f95903be7ae7ab055f036d0e7c939caf1e7cb47f1bc037c5f926816faaf34d065fd6f9a69096c62e70be8120a95cc91fb4db6d4c7abb6e2e22973cef21bbdd2626de69c9f31eb6db6d66e0b5f931dd6dab11f26686f3e5c0d7e27c4de0735dd0bf8e39eb9be57ccde09bed7cd3c137c7f966806faef3b5806f9ef3cd04df7ce79b05be05ce371b7c0b9d6f0ef81639df5cf02d76be79e06b75bef9e0bbd0f91680ef22e75b083eea2f1781efb1ceb7187c746dd70a3ebacebb107c74cd7791f3d97e627206e2393ff551613cea9fc1f738ea9bc1b784fa65f05d4c7d32f896426cf22d837e857ccb9d8ffa28fb5ebf2b0f04491d1385f0185e93f476cd96ed76d725bfdd700e6c7d30a2f500c459035a6d70e504ef0f69c7d8741d4371c85f07e59d5097ea911e749e2176dbefaf75e50d253ed7ef7d2e0775d646b47f2048b6fdeb3c9e751e733db49f29678f6ace8e79293b67af84ba7eeed135cf44ccd93dc0917cce767468ce8e79293b6707a1ae9f7b74dd3b1173f61ae060c8d91e9e9c2de435678be36041109d7bf4dd6722e6ec31e0483e67bb3467c7be949db3f7415d3ff7e8fbef44ccd9db8023f99cede9d16b83312f65e7ecf3a1ae9f7b3416331173f601e060c8d943dacf8e79293b675f0b75fddca371c18998b32f028ee473b68f29673b346783e29c661044e71e8d514fc49c7d083892cfd9c33a3e3bf6a5ec9cfd18d4f5738fe64b2662cebedb95ed3cc3b7dc3cc302f07ddbf916026ff2b97da49d29b7db35b78bf77a0441748ed2dcdd44cced475cd9e6f177e1de03f27d8fee4b00dff79def22f0fdc0bb6783e918e8d66360ec6d2af718f819d4f57399e69127e231f06de060c8d91ecdd9b1b7a9dc9cfd0bd4f5738fee69988839fb4be060c8d95ecdd9b1b7a9dc9cfd3bd4f5736fa92b4fc49cfd2f57b6d70b3f71d70bcbc1f753e75b01be9f39df4af0fddcf95681ef17ced706be5f3adf6af0fdcaf9f2e0fbb5f3b583ef37ce5700df6f9daf037cbf73be4ef0fddef9bac0f707e7eb06df1f9daf077c7f72be5ef0fdd9f9fa9ccfde9347f75e7dd1f9ecbe258d068264f72ddd6349dba6f595e310bbc98bdd348eb19bbdd8cd11b15731c4ce420c5a32defa009457f1f2e473c083b156271fabc3b6bd2d187bdb57034f9ea1ed598831169e3cf0b427cf139e3f0bc96f37dcc76d9ea65988d506edea6068570662d1b6699de2e5c087fd7747046367f28c850cc4a26dd37a2730920fcf27745ea7e3c79e0f97644678198ea5f09a88e2d1f39f886335f8a9ce375b46d8963bb646781fcfaded9e8f292fc3bca058b46d5aa7788dd09ef6f1672c8c9531ef3172f511198845dbf663e3f1be6afc351bd37ecd81ef3cf449854afba446601b8feb94b87d2d2536c7f92a0331a86f23cd0be0a73ab3dc0f126cdfb61dfa5d86e3af50eef51bf607c9e771218fc7f558783a8087e3d8673a5ef378deff67906cae75795ab57b5ae5a04e27e8d7c5a05fa9eb108aa7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1fe0b9cdfa47a2b853092af003c1ce3fce133a0dcb668fb765ee7c730af93fcbc45218f7396748fe132afcd7550e7af9991ba3f87f9747f6e10e73457f26a37a6fb2c1a8373e76239e710e3e681a3e62f5b138b5d38cc35df66ef51b3cf216bf3745d19a129c37d2aa334cd789ae27d8a2b3c1e9ba7736b47d838e6feca9d8b44ada89ce4dc1ede63c0bb5f8afd07e5424d30baffc0f34c77e2b147cf61d27c79b717bb0eeafc6f6664dfd0bda8f4bfeefc7b9e6c9d1e6fdbf49965e0eff1b63dcd7d9638eabdedb7c167a9ceff419ffaba9ae05f9a71dcff81fd72006dc56500ca386f9efc79b8388fdf51064f17f070f4334cd71b793c06929ec7eff1b48aba8ea13adda05f0f837e51d7a2b44ef194599995599995599995599995599995599995599995599995599995599995593e33fe569458b350af2084719cee7d08e733e8f92fb47d3baff39c9a91b8dcf37034e7b4dc6b731dd4f946cd48dd17b8726370eefd0e71fb92613eafe4bea4788dd01e9c0be2fa3d77a7c7d319a105955b138b5d9cc74f5ee39179fc0e4fd74284a65cc72bceb1a2a678bcb67b3c3837da189c7b6f4916b6331ef70ec5e505c5c363a9137c54c6df4773ec673c97f8f7f5503c9cbf7ed8693b2de0daf7853c67bfd10b6d1a08cecdef3aa8f32ee8fbdee3ca780f07de3bf248c4fbb4949aa726fd589e65972fcefbae01ce018883b1d7026b42b1db3176c619c5217f1d943f59335297ea911ea435b1db63849e0986ecfee7dabdcfe5a04e5f44fb078264dbdfeff1f47bcc769fbc1ff2ec1138ff73f5497d311a2d038da80e5e0771dd93e7f791fefd8d78df5e835707af59a8ce17a18f8abb7f34ea9e43aef358dc3d8751d7c65dc0e8b7d1bfcfb3daefd3fa21f41749dfa7f543c821bc4f2bf0b6bf1cb64f5c0d41fcb985eafcd4dbbe7f4d4e9fc1fbc0a8ce2fa0bf6872f72c3606e75e7fe33d53e3f1fd2aee3e698a87d735786cffbbb65be65ea83f902033e604b2e07502d5f993b7cf7a62b857477cf6af319f25ade83954f8fdc5d7cfead0079f19484487e231dfefb585f2ba0fda4275fedbbb064cfebaa5780d987c5b475f93503fd019d156aaf33f70acfd1daef1683fe1f78e86da73dfa7a5d43520e967db3cdecf07c6d8129e0f5c5f3b52d77fce2f695deef381bbbdcf497c3ef03f20cf1ae03e74aebe7a6d8c46cb4123aa83bf0da2f3083ecb37ea1cc3756f7fdc3926ea1994d83f37d58e3f9b3fae16758d4075e8b3788dd0e298a7399dfdbafe78219d2f93bc6f187f2bd10671f1b7126d4c7ae641b70158c7eb82f3193bcf143bee99d3f971881df7cce9f188ddecc56e1ec7d8aab96a2e497386672287bf3fc36796daa5d4752931e4e073352960ac4d01635d0a18eb53c0d89002c64929609c9c02c62929609c9a02c62c309ecf733b833e854af5e1da5fa5ae353036c3ff2e2994fbff3b98ff974ac96b1f8ccdf09d2ed4625530762df07b1ec7b31fcafd5f2fc480ffbb607a0a1867a480b125058c3353c0382b058cb353c03827058c7353c0382f058cf353c0b820058c0b53c0b828058c8b53c0d89a02c60b53c078510a181f9302c6c7a680f17129605ca28c8930aee0652c54ca687938fee7dfa3f99f630c3cf9a87b4e997e7b52f6ff5b637e3e697ba5cf8dc37b4b78ff27dca37bb61dc7bd23e53edbaed4ff5b65622c54cac8751f3bfe8e672c3cf8bbc8a8dfd63030162a65e4fafd0bfe466f2c3cdda0595784660c8c854a19b9ee952bf75e4ebca7bf3b423306c642a58c785f75823ca1663d65f0f482663d119a3130162a65e4ba2f390b31c6c2d3079af54668c6c058a89491e9b76da1667d65f0e06fc0fa223463602c54ca6879d63069d65f06cf1ad0ac3f4233498cc893f473b2fb236271fc66b0dcb61303324e4901e3d41430e27d121cfd57a9fb24fa79f52954aa0fd7fe2a759f04c666f87d4ca805fe1ee2df69b18e97a7e47d12187b3d9316f87b957fa7c57ae0e1f8fd4c16628c85871872f0b9e929609c9102c6961430ce4c01e3ac1430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01237e5765b8562cf9fd65fd048f1df75d65a2c78efb5e32d1636b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae79262a7618c5f19271e23f2b426c793c7b663ac01016d1f88e0c930b51d636d14d07662481be3861430ae4901a3ea58bc07b11246cbb389896763193c9b80673313cfa632783603cf96e479c29cda5c060f31e4e0736b52c0b821058caaa3ea28895175ac1e1d955119955119cf07631afa70654c453e162a65b43c5b93e70935db5206cf56d08c3ed7cecb58a894d1f26c4b9e27d46c6b193cdb40b3ad119a3130162a65b43cdb93e70935db5606cf76d06c5b84660c8c854a192dcf8ee47942cdb697c1b30334db1ea1190363a15246cbb333799e50b31d65f0ec04cd764468c6c058a894d1f2ec4a9e27d46c67193cbb40b39d119a3130162a65b43cbb93e70935db5506cf6ed06c5784660c8c854a192dcf9ee47942cd7697c1b30734db1da1190363a15246cbb337799e50b33d65f0ec05cdf644682695714d0a1837a4809159c742a58c96671f13cfde3278f601cf254c3cfbcae0b904781e9f3c4f98539794c1430c39f8dc9a14306e4801a3eaa83a4a62541dab4747655446652c8f7120058cbaaf95512a23c3f7ab92bfa1b96482c76ef262375549ecb8dfd04cf4d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e6b9a4d8fb938f5d28f71933fb8187e399374cedccdbed5eeab6f5cf04f5b35a5de6697589a7550eea5c0afa5dc6a05f06e2d2b6699de295cb7cb10066a6d805dbbf4c81f6538c0d9e1e36fee54c6d8febeb2f9fe0b1e3fafa891e3baeaf9fe8b135cf35cfab21b6e6b9e67935c4d63cd73c97121bcbf5c1c8753b3dffd46ee309ae5ce7d69195fc54e7f1938aafd3023d863862eb31a4e78a6a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9ecbcbf31cbc5f330e3c81c71394e059248c678e309ee9c278a608e359268ca75618cf7a613ce3713f5f393cbb84f16c17c6d32b8c67b1309ee5c278e60ae32908e399218ca74b18cf54613c5b84f1d409e3d9288c272f8c678f309e25c278e609e36911c6b342184f56184fbd309e4dc278560be3592a8c67af309eddc278fa85f1ec10c6d3278ca75b18cf7c613c1dc278660ae36913c67381309e46613c5b85f13408e359258c679f309eb5c2781608e399258c27278ca74918cf24613ceb84f1ec14c6b34d184f8f309e85c2783a85f1cc16c6b35218cf34613ccdc278360be3992c8c272380271b9cfb4cb22cbcbf1f7c35de67edf540f3cc91f7af70fe1af8cc95ae5c1bb1ed2bc047bf0dbf32e2b3a8d315d0960157ce3fba25d409630dc03ac56b048e2b85f04c16c6b359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278b609e3d9298c679d309e49c2789a84f1e484f1cc12c6b34018cf5a613cfb84f1ac12c6d3208c67ab309e46613c1708e36913c63353184f87309ef9c278ba85f1f409e3d9218ca75f18cf6e613c7b85f12c15c6b35a18cf26613cf5c278b2c2785608e36911c6334f18cf12613c7b84f1e485f16c14c653278c678b309ea9c278ba84f1cc10c65310c6335718cf72613c8b85f1f40ae3d92e8c6797309efdc278d60be3a915c6b34c18cf14613cd385f1cc11c6b348184f4d040fc3ffbf0c79e8fe35da36adef17129b613f84fff7f32aa6365dedb655efb64bfc14af0eea5ce33a0a7b7f157e96b8fcfb0df1dc7435687435535b687f64bcfdc31d1befab0c8021f0f409227838ee47656ae7a83c4cf0ffcfe6ad56d7785af9fb2e0775ae02fdae61d02f2ab7ff750c000f5de7106b16eaad17c248becb9979b2d0665a4a1d03d7000fc731c9d4ce3057aff5dab43e4277aa83b97a2d433ba38e1d5abf167836ba32b166a1de46218ce4bb9a99270b6da6a554ae5e0b3c1cc70e533bc35cbdce6bd3c608dda90ee6ea750ced8c3a7668fd3ae0d9e4cac49a857a9b843092ef1a5e9ece2cb4999652b97a1df0701c3b4ced0c73f57aaf4d9b2274a73a98abd733b433ead8a1f5eb613f28b33247315b1efa9d0eb166a1de66218ce4bb9695a7339f8536d352aa1fbb1e7838fa7926ddc37eec06af4d9b2374a73a98ab3730b433ead8a1f51b2262b706c96a71e318b4b83182e7c671d682e295cb7c550a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7f161569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d5b93266cb43cf4522d62cd4db2284917cd7f1f284bf0bda128c5e32defa00946f049eeb19f4616a67780ff901af4d5b2274a73a787c1d606867d4b143eb07603f1c2883f9861432abce95315b1e7afe38b166a1de56218ce4bb9e9727ecc7b606a39752fdd801e0e1e8e799da19f66307bd366d8dd09deae0f17590a19d51c70ead533c6556e63866cb43ff078858b3506f9b1046f2ddc8ca53087fdfb82d18bd94eac70e02cf81c4798afd1883ee613f76c86bd3b608dda90ee6ea218676461d3bb47e08f64339cc37a4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7ead1d9f2d0ff8321d62cd4db2e84917c0758793ac27987edc1e825e3ad0f40f910f01c4c9ca738efc0a07b38ef70d86bd3f608dda90e1e5f8719da1975ecd0fa61d80f139df98614326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03c3b5c9958b3506f871046f21de4e5099f7bb02318bd94ba6fe730f01c62d087a99de17d3b47bc36ed88d09deae0f17584a19d51c70ead1f81fda0ccca1cc56c7976ba32b166a1de4e218ce43bc4cb13f6633b83d14ba97eec08f070f4f34ced0cfbb141af4d3b2374a73a98ab830ced8c3a76687d10f683322b7314b3e5d9e5cac49a857abb843092ef302f4fd88fed0a462fa5fab141e0e1e8e799da19f66347bd36ed8ad09dea60ae1e656867d4b143eb47613f28b33247315b9eddae4cac59a8b75b0823f98e30f364a1cdb494eac78e020f473fcfd4ceb01fbbc96bd3ee08dda90ee6ea4d0ced8c3a7668fd26e0d9e3cac49a857a7b8430926f9099270b6da6a554aede043c1cc70e533bc35c3de6b5694f84ee540773f518433ba38e1d5a3f063c7b5d9958b3506faf1046f21d65e6c9429b692995abc78087e3d8616a6798abc7bd36ed8dd09dea60ae1e676867d4b143ebc781679f2b136b16eaed13c2483eecc7f631f1347a3c8d115a4cc4d84d5eeca62a89ddecc56eae92d89ae79ae7d5105bf35cf3bc1a626b9e6b9e5743ec6acd35d5bc3a35cf9c47cd33e751f38c6a2e52f37f2617bb2b178c2c35108b617cae7d2c638ec8b34818cf1c613cd385f14c11c6b34c184fad309e5e613c8b85f12c17c63357184f4118cf0c613c5dc278a60ae3a913c69317c6b34418cf3c613c2dc2785608e3c90ae3a917c6b35a18cf52613cfdc278fa84f1740be3992f8ca74318cf4c613c6dc2782e10c6d3288ca74118cf2a613c6b85f12c10c6334b184f4e184f93309efdc2782609e359278ca74718cf42613c9dc278660be359298c679a309e66613c9385f16404f06483737fdb81bf27a8051fdddfbf0f7c4f74e5fde0ab898841db390e3e1acfa56dd8f3d58299e732d4c0676e8ee07a62443c8a7373c467c743778c3500eb14af11386e16c23359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278d609e399248c67bf309e26613c39613cb384f12c10c6b35618cf2a613c0dc2781a85f15c208ca74d18cf4c613c1dc278e60be3e916c6d3278ca75f18cf52613cab85f1d40be3c90ae359218ca74518cf3c613c4b84f1e485f1d409e3992a8ca74b18cf0c613c05613c7385f12c17c6b358184faf309e5a613ccb84f14c11c6335d18cf1c613c8b84f1d444f0ec67e2897b9ec27e01b1edb8375d0bd2985816de1f8fdf29edf71869fd1830920fefd3cd33f1c43d83222f20b6d5623594ed9285f7f177265c3995f718693d2aa7f03ecbd54c3c71cfed582d20b6d582e606e81e802cbc8ff75573e5d46a8f91d6a372aa999727fcff01ab82d14ba97b8df098e3d8874cedcce3f197e03334229f91bccad32a0775c6e3bee2b8fe80e229b332c7315b1e9afb22563c9f8dc7ef96c6c218757e65e009fbc7b660f452aa7f3c063c1ce70fa67686fdd809af4d6d11ba531dccd5130ced8c3a7668fd4444ecd620592d4e8e418b93113c27c7590b8a572ef3fe14324bd0d9f2d0bd9ac49a857a2b8530922fcfcb13f68f2b83d14ba9fef124f0709c3f98da19f609a7bc36ad8cd09deae0f1758aa19d51c70ead9f82fd500ef3891432abce95315b1e9aa321d62cd42b086124df31569e423e0b6da6a5543f760a7838fa7926ddc37e6cc86b53214277aa83c7d710433ba38e1d5a1f82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2992d0ffd769858b350af430823f94eb2f214e71d3a82d14ba9798721e03995384f71de8141f770dee1b4d7a68e08dda90ee6ea698676461d3bb47e1af683322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf40c7962cd42bd4e218ce43bc5cb13fe6eab3318bd949a77380d3c1cf3324ced0ce71d6ef1dad419a13bd5c15cbd85a19d51c70eaddf02fb419995398ad9f2d0b30789350bf5ba8430926f8895a7387fda158c5e4af563b7000f473fcfa47bd88f9df1dad415a13bd5c15c3dc3d0cea86387d6cfc07e2887f9440a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975ae1e9d2d0ffd4f4362cd42bd6e218ce43bcdcad311ce3b7407a39752f30e678087635e8649f770dee1acd7a6ee08dda90e1e5f6719da1975ecd0fa59d80f139df9440a993537c68759734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426e589e1e5726d62cd4eb11c248be5b7879c2e71ef404a39752f7ed9c059e330cfa30b533bc6f67d86b534f84ee54078faf618676461d3bb43e0cfb419995398ad9f2f4ba32b166a15eaf1046f29d61e6c9429b6929d58f0d030f473fcfd4ceb01fbbd56b536f84ee540773f5568676461d3bb47e2bf0f4b932b166a15e9f1046f2e139ae8f89a7d1e3698cd0e27cc5b65af4bbf205ee350beff7032357dfd2e731d23ae638f91a81a79f89a7c9e3698ad0e27cc5b65aac85b25db2f0fe5a60e4caa97e8f91d6a372aa0978d632f1347b3ccd115a9cafd8568b75ae3ccdbd66e1fd75c0c895536b3d465a8fcaa966e059c7c413d727ad1b87d871c7d778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c478563a7142300065c06a08cdf1538ae3d99da998ffa3eb6ce6b137e1fc33187f3f57d439995398e9969dca233ebc5267d028f879661662dc6730cb2df6b93b431c872994fa4905975ae8cd9c6be2df9d89d592f36e913783cb4dcc6ac05533bc3fee0f6205a638a97833a98a7b733b433037169dbb47e3bec8772984fa4905975ae8cd9c6be23f1d8c567b3636cd227f07868b983590b9e7616fb833b83688d295e0eea609edec9d0ce0cc4a56dd3fa9db01f945999955999955999955999955999955999955999955999955999955999955936b38dfda4c46317c7ef3136e913783cb43c89590b9e7616c7efef0aa235a67839a883fbfc2e867666202e6d9bd6ef82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec27271f3bfc3d0ec6267d028f879627336bc1d4ce70fcfeee205a638a97833ab8cfef66686706e2d2b669fd6ed80fcaaccc51cc36f653128f5d9ccfc3d8a44fe0f1d0f214662d78da59ec0fee09a235a67839a883fbfc1e867666202e6d9bd6ef81fd500ef3891432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c3d3adbd8f7261ebb231cbfc7d8a44fe0f1d0722fb3163ced2c8edfdf17446b4cf1725007f3f43e867666202e6d9bd6295e35309f4821b3e6c6f8306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80d1bfba9c9c70e7fcf8eb1499fc0e3a1e5a9cc5a30b533bcffe5fe205a638a97833a98a7f733b433037169dbb47e3fec076556e628661bfb0186d8592f36e913783cb43cc0ac05533bc3fee0c1205a638a97833ab8cf1f64686706e2d2b669fd41888d7a27143bbc079262d4b857eb7b9a2bd782efe9ae5c07be67b8723df89ee9ca0de07b962b4f02dfb3a13de47b8e2baf00df735d791df89ee7ca6bc1f77c57ee07df0b5cb90f7c2f74e561f0bdc8956f05df8b5df936f0bdc4956f07df4b5df90ef0bdcc95ef04dfcb5df949e07b852bdf05be57baf293c1f72a57be1b7caf76e5a780ef35ae7c0ff85eebcaf782ef75ae7c1ff85eefca4bc0f75084ef0daefc54f0bdd195ef07df9b5c793ff8deecca53c0f716579e0abeff8032bdbed5952f00dfc3aedc08beb7b9720e7c6f77e526f0bdc395a781ef9daedc0cbe77b9f274f0bddb956780ef3daedc02bef7baf24cf0bdcf956781effdae3c1b7c1f70e539e0fba02bcf05df875c791ef83eeccaf3c1f711575e00be8fbaf242f07dcc951781efe3aebc187c9f7065dcbfffe9ca0f808ffa9507c147fdcad3c047fdcad3c147fdca33c047fdca33c147fdcab3c047fdcab3c14779f71cf051de3d177c9477cf031fe5ddf3c14779f702f051debd107c94772f021fe5dd8bc14779f712f051debd147c94772f031fe5ddcbc14779f70af051debd127c9477af021fe5ddabc14779f71af051debd167c9477af031fe5ddebc14779f710f828efde003ecabb3782afd595df04be0b5df9cde0bbc895df02bec7b832f6338f75e5b782ef71aefc30f8a82f7c1bf82e76e5b7836fa92bbf037ccb5cf99de05beecaef02df0a577e37f856baf27bc0b7ca95df0bbe36577e1ff856bbf2fbc19777e50f80afdd953f08be822b7f087c1daefc61f075baf247c0d7e5ca1f055fb72b7f0c7c3daefc71f0f5baf227c047e771ea67ecf16c8f41d28134b23e6a735b445bc83719da3210247b4d47b168dbb4de018cb40f0ae3cf58182b63bbc76879ba1834c3bca2a5d4f78f2ee0e964e0616a67f8fda3db6b5387d7a61cd4b918dad9cdd0ce0cc4a56dd37a37c4e6d8e7a845bddbee524f8b3aa8f3077792b3e7ce523ad2366cfe1622dad2c7dc16da36f54b7de310bbc78b9df762637f4c4ba9e3ab07987b1998ed76fb93df6e787cad71dba29ca2387968d35ad020a93661ec8c338a43fe3a28ffa365a42ed5233de8fc45ec3697695f22bbffb92eef7339a8d317d1fe8120d9f6f77b3cfd1eb3dd277f6b19e160381ec21ce8f338683d0fdaf5c768d707da511d3cff1598b4ebf5787abdd89687ae71bac147d70ac48fd7596de3c0edf77bdd11dce4eb01c6a86b9df6e4194b5eebb40323f97a81a78749337f5f2ff5f4c1f3728357873e5b07759adc97bd69c1e8ef1f54d71e774b3223eda2efe0ff0c92edd31b18f4c2f18100f4093c0d03d08bda59cfc03335181923383b3c74e6e04d83970e1e3c9201b43a0f135f3311cda8011f966b237c41307a2804876469280487646b3c59700886eadbaf52b65934dc3078f2f8f0134e0d9e3a7ce6ced3c38347f60cdd84d4f51e3d92c6b50049d147cbe46064d066204836791abc58a5926732bc4e62e0616a6778d29be2b5a9c16b530eead4c37b5318da9981b8b46d5ac70160f26176d2fb386150e3b505b3780abcfafb36d10651c0c7c0f6330ecebe57e7846d70f0242ef5187614d15ec9d91d6147056d6f6d47fdec616747f5ec8591edc8ed289d1d95b3a37076d4cd8eb2d951353b8a6647cdec28991d156b0d8aa35e1701cf1781d18e6ad9512c3b6a65bf49dab3821d85b2a34e7694c95e4dd86f29f60c6caf38edd5913d23da33a1fd3665bf59db338c3d7bdb33933d9bd8ab237b5564af62ed559d9d99596f6c83d37aa3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e31f6f8a038a27ca9b1cb8c5d6eec09c6ae3076a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b83e21d1e278d9d323664ecb4b15b8c9d31763628ce12d959213b0b64677dec2c8f9dd5b1b33876d6c6ced2d859193b0b63675dee0d8ab32a7676c4ce86d891703bf26d47baedc8f63382e2c8b51da97e76501c89b623cf76a4d98e2cdb91643b726c478aedc8b01d09b623bf76a4d78eecda915c3b726b476aedc8ac1d89b523af76a4d58eac3e1414474eed48a91d19b523a176e4d38e74da91cd8783e2c8a51da9b423937624d28e3cda91463bb2684712edc8a11d29b423837624d08efcd9913e3bb26747f2ecc89d1da9b323737624ee93c61e31f629639f36f619639f35f639639f37f685a098935f32f665635f31f655635f33f67563df30f64d63df32f66d63df31f65d63df33f67d633f30f643633f32f663633f31f653633f33f67363bf30f64b63bf32f66b63bf31f65b63bf33f67b637f30f647637f32f6e76064d41e3b8abfbb151a413e383c3c78f2f470ebf050ebc95b4f0c1f3f7de2ced6db8f0f1f6b1dba6df0ccd11343b7e387dfeaba261a1edf78e6ccc13b5b8f9f3a327847ebd0adc3ad43475b0f0ddd7aeac859fcd017dc87169c1bf1e09123f1c17e50f328487f5261d03fbacfd1c4c3ced26dfb4b2582fcad920fcda8adac4197b8330b7d2bbdac7815d77af6c4d0706bbef594f97bf084f9cce091b6567cefac11f9ec70ebd9e18367865b8f9e193ad9dade86dbbd7a4a058df87d4b051fcacd1c7bcb83ff079bac954d69010400", + "bytecode": "0x1f8b08000000000000ffed9df7771c45b6c77b64490e638de51c018171906549a3916c598e12b08071029b60927192c1605bc61669030b1b6161173692173647364736e765132cbb0b0bcbe665c30fef0f78efbcc379b77aea3e7d55aed6d1882e71dbdc3ee7baabbfaae9fad4b76fd78cab7b7a725179f93745ce96c750cc8f8e5df8efdd765d7c694b5b8afb2a86e4cc6584b32a239c6332c2599d11ce9a8c70d66684736c4638c76584737c4638276484339f11ce8919e1accb086721239c9332c2599f11cec919e19c9211cea919e19c9611cee919e19c9111ce9919e19c9511ced919e19c9311ceb919e19c9711ce1332c2796246384fca08674346384fce08e7292972360127cf859f6ad70bec7aa15d2fb2ebc576dd68d74b6c1fabedb6d9e7528a668a16e76fad8699c24c8a979cbfb55374502ca3586effd660ffd649b182a28b6225c52a8ad5146b28d652acb39ef4509c46713ac51914afa23893e22c8ab329d6539c43b1816223c5268acd145b28cea5388f622bc5368af3292ea0b8d061b988623bc5c51497505c4a7119c5e5143b28aea0d849b18b6237c51e8abd14bd14fb28aea4b88a623fc5d514d7501ca038487188a28fe230c5b51447288e52f4535c4771bde3d90d143752dc44f16a87f33514afa5781dc5cd14afa7b885e2568a3750bc91e24d146fa6780bc55b296ea3b89de26d147750dc49f1768a7750dc457137c53b29de45f16e8af750bc97e27d14f750dc4b711fc5fd96854f8407281ea47888e2fd140f533c42f1018a0f527c88e2c3141fa1f828c5c7283e4ef1098a4f527c8ae2d3148f527c86e2b3149fa3f83cc51728be48f1258a2f537c85e2ab145fa3f83ac56314dfa0f826c5b728be4df11d8aef527c8fe2fb143fa0f821c58f287e4cf1138a9f523c4ef133c7f39f53fc82e29714bfb2da1376fda45dffdaae9fb2ebdfd8f56fedfa7776fdb45d3f63d7bfb7eb67edfa39bbfe835d3f6fd77fb4eb3fd9f59fedfa2f76fd57bbfe9b5dffddaeff61d72fd8f53fedfa5f766dae8fe52797cbe3a281a53b4a69cce9e8ed32f3e36ca67bfdcd5cdb1963ffc6eb06ab57db6d5ee7ac5e63b76b1cbdd66ed73afb1967b7c7397ac16e171cbdde6ed73bfa14bb3dc5d1a7d9ed698e7eb2dd3e19f4bcfd5bb963e595d1c65829071ae75f156835561b035a2def0eb4b156ab018d8f6f2d68e3ad3616b409561b075ade6ae3419b68b509a0d5592d0f5ac16a13419b64b53ad0eaad5600cda6663409b42956ab076daad5268336cd6a53409b6eb5a9a0cdb0da34d0665a6d3a68b3ac3603b4d9569b09da1cabcd026daed5668336cf6a73403bc16a73413bd16af3403bc96a2780d660b513413bd96a2781768ad51a40e3f3f264d04eb5da29563339c5e35cfc1aab5781762a9fcba02de0f318b4857c0e83b688cf5fd01643dbac35f2f90cda12ab713e9bbf2db7e5ee28adb1acb4dbecb733edfdd29ecd7ebbd2df6fd18c8d2ba301afbba19d4ef06a952da7784f401bb69db3c1edb05e0de533a12ed7633f784c627633ceacb0e55543bc6eb9f3ba02d459e1e97f77946effbb1c9e2e87b906ca8172769fe6ecb0978a73f67ca8ebe61ebf3f1e8f39bb1e38d2cfd9f676cdd9612f15e7ec6ea8ebe61e7f563b1e73f622e00890b39d6172b654d49c2dcf8f44913ff7f8ff0dc763cef60247fa39bb4c7376f84bc5397b33d475738fff0f7b3ce6ec51e0483f673b3bf5b3c1b0978a73f64ea8ebe61ecfa71c8f397b2b7004c8d9dd3ace0e7ba93867ef87ba6eeef1dcdef198b3770147fa39db152867db3567a3f2b5ae28f2e71ecf331f8f39fb1070a49fb37b747e76f84bc539fb15a8ebe61e5ff3381e73f653b66cae333c61af33cc03ed49ab9d00daafad7622684f59ed24d07e03d70659fb2d5f3704ed77563b05b4a79d6baa467bc66aa782f67bab2d00ed59ab2d04ed39ab2d02ed0f565b0cdaf3566b04ed8f565b02da9facd604da9fadb614b4bf58ad19b4bf5aad05b4bf59ad15b4bf5bad08da3facd606da0b562b81f64fabb583f62fab7580f66fab2db39ab926c9d7be7e6cb571d0f7ee28bd1c8daf774583979cb3dd0de52561798a8568f07d40dcd6d2f4db6a377d6f8a86dff7a5c0d31ca0ef796863383ccdc0d3923e4ffc3db9d6f4f71b1fe326c7d33cb4d504fd2a06e8570edae27df336b757000dc78da287b12d7dc612deebc4fbe6ed3660640dc7311e87f9fc31ef31ff01de00e752fc3983dbe3efff32c752d0b9ced7eb07d8fecb6a75f0771cd35b1c2d505ec679c16df1be79bb1518b93f2da3cf581a2e63b3c3186a8cc8415bbc6fb76d3cdf978cbe67c33aae05d05e8631a934d231a90ed81a81b131908f49c75a4adb21deaf72d0068f6dec792be85ce7d9aaf2da8c6d1372036c01cebf52a59fdf703c483f8f4b453caf87c353049e10e77ea0f3b588effb2f46e9e65ac9f1aac5f1aa0075dac0bf5200ff86fa1cc2ed29b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb37c66bcff02af6f72bd46218cacb5024f8879fef8bbe4bc2fbb36d7751e80eb3ae95fb72815f19a25dfb7b7d0e97335d479343750f7615bf65d1bc46b9a8d61bd1bd67d1675d1b1d762435e434cba0eecbb7ed9905adba53da1aeb799e75c9867123439be367a3c0d709fca204f738ea7787fdc6287c7e4e9f355036c21aefd557a2d12bde2729ad7f6f01e83b0c7a53c7e702e544583c70f7c9f694fbdedc1d730f97a79bbd37635d4f9466ee0d8f03d90fc5b07ee3d4fa64e87b36f7ecd42d03b9c7dd7dbd732478db3ff26782dd7f9368ca9bb205743dcff81e372047dc5a51bca78dd3cfdf7e1f275fc62053c25e00931ce04fabc51c47320edebf81d8e57becf315ca71dfceb08e09fefb3286f737bcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9f19bf2bcaac79a8d72a847194ee7d88af67f0734778ffe6bace96aa8176435f87e36b4e8b9c3e57439dbbab06ea6eb3e5bae8d8fb1d928e6580eb79431e4b6eaf0efa83d782427d9fbbcde169f378c1e586d4da2e5fc74fdfe381ebf845c7d7568fa7a1ce57bcc68a9ee2f9dae2f0e0b5d1bae8d87b4bf2b09fd1b87728292fb83d3c97da40e3327e3f3ac471c6f712f7be1e6e0faf5f5f63bdad8f421dfb5231e4b8b10cfad41d1d9bdfd550e7308c7d476c19efe1c07b476ef5fc9d97a1ae53b37f819ee3161fdf15c0d90ded60db5dc09a52db6dd876ce06b7c37a35946fa91aa8eb3ea78cbd6676738eb8cf52f3bdaec5795d01ea2cf7f4bf3b4ab7ff9d0e4fa7c36c8ec9759067b7c2fb7fa831697982470bc123ae839f8342bd77baf757baf715e2385aebd4e1d756439ddb618c4aba7fd4f71e10fa7d8cf7ed7b1f73df1786739fe72bfd3eadfb60bc48fb3eadfb2087f03eadc8d9ff22d83f73d546c9ef2d5ce72167ffee67727e0dde07c6751e81f1e229f8ace37efec67ba646e3ff5749f749737bf8b986ff369cbe1be66550bf3b4566cc0964c1cf095ce793ce31eb48e05eea79eda309af65aff83954f8ff17d73fe343eacf90b5e77ca7d317ceebe5d017aef345e73360a8e77ca7dfd7c19f49781c68f3f495eb7c0dceb5c7e0331e1f27fc7fc7e39ebff332d467407ceeedcaf4fb1c1f5f7cbe6b37b4836daf06d694da6ec3b6f93320b7c37a35947f0a633ad7633fd86b6637e7087f8e4276f775edceeb0a50a7cbd3ffee28ddfeaf7478563acce6987c0bf2ec71f80c186aacee4af0681178c475f0bb41fc3e82cf90f5cd75bc5cff9fc6cf52383e3f15745ecdfffee7ceabf93e232c723cc6cf08cfc0389bf7d475e70bf9fd32cdfb86f1bb124dd0eef39e76bb53f6b3197ceb866dfc5cf072b61de0b9a5f17744f0b982cc804b379499a100afabca00e3980c30566780b126038cb519601c9b01c67119601c9f01c6ffffbd6fc18cf90c304ecc00635d06180b19609c9401c6fa0c304ece00e3940c304ecd00e3b40c304ecf00e38c0c30cecc00e3ac0c30cece00e39c0c30cecd00e3bc0c309e9001c61333c0785206181b32c0787206184fc900e37c654c85717158c6d248190d4fa8df27ace437f146e3f709977ada0a705da45469dff15a4988e7a755fa7b89cc50888efdfdaf408ca591321a9e96f4792afe7dcd16f0ccf73b9801185fd26f48497a6e1bde9fbe242c63e9a53c5b2ec4b31647fafc30bcc7604958c697f48cb310f71054fa8c33dfef6e2e09cb581a2963a87b42f0fe93e1f0f8ee13591296b13452c650df83c0ef6a0d87a71d3c2b793c0bc0581a2963a87ba62abda70fefed6ef77826891179d27ebe68bba7ad6502face0c59631c9f01c6091960cc678071620618eb32c058c800e3a40c30d6678071720618a76480716a0618a76580717a06186764807166061867658071760618e76480716e0618e7658051ff5fa88c2f3723f234a4c73368fe03db0af1bdd64afbbedcc393e2f73e07f51ddb0af08c938afb8ecf02c912e3b20c30067e9e8dfaa88ccaa88c7a5eab8fe219d547f5511995511995f195ce9885315c1933918fa591321a9e15813cebac80670578c6af5b1296b1345246c313e2d9b8796863383c5de0d90a8f6701184b2365343c019ee3177bd655010f3eefaecbe35900c6d248190dcfaa409eadac80671578b6d2e35900c6d248190d4f886716e6a18de1f0ac06cf56793c0bc0581a29a3e159933e4fecd9ea0a78d68067ab3d9e05602c8d94d1f0ac4d9f27f66c4d053c6bc1b3351ecf02309646ca6878d6a5cf137bb6b6029e75e0d95a8f6701184b23651c077a8a3cb167eb2ae0e906cfd6793c93cad89101c6651960cc828fcaa88c9218f5bc561f2531aa8feaa3322aa332669771790618f5582ba354c69ef4194b9532f6004f77fa3c6d81fa19fffed469765f293e13a164bc3addf16a9de35501ea9c06fe9d1ec0bf1cb4cbfbe66d6eaf52e6530530076abbc4bf8bbcce696f99e38759ceb0eb1ad0f137dc5f65cbfcdb735c1f7f878ceb6cb63ff4c1bf69c94b15f4f78cf4fbdb36d4b9cded214f8b309ea5c2787a84f1cc15c6335d18cf1a613c9384f1ac14c6335e18cf42613cf8bb5b12783a85f1cc13c6b34818cf0c613cf5c2782608e32909e3a916c6d32a8ca74918cf7c613c3385f1ac15c6335918cf62613c79613c2b84f1d408e359258c6781309e59c278a608e399288ca756184f51184fa3309e66613cb385f14c15c6b35a184f9d309e2e613c6385f1b40be399238c679a309e82309e71c278da84f1e404f0e4a363ef59c8c3df7b40ab725e6bc6abffad1ff8fb9956af82d79c65cb633cfb3e1334beb67b96e7b5e8d399d0976e5b2ebeb425f609dbea866d6eaf0e38ce12c2d3268c679c309e82309e69c278e608e36917c63356184f97309e3a613cab85f14c15c6335b184fb3309e46613c45613cb5c278260ae399228c6796309e05c2785609e3a911c6b342184f5e18cf62613c9385f1ac15c6335318cf7c613c4dc2785a85f1540be32909e399208ca75e18cf0c613c8b84f1cc13c6d3298c678c309e85c278c60be359298c6792309e35c278a60be3992b8ca74718cf52613c2dc278aa3c3c3d8178f8fa2def9bb77b84b41de038c4df8b3f3b509fd6db7dd5d8fd323fb7570d75eead2dafcde75d7c2d73b9d7dbf15c5e0f1ead0fd4173e1e39e7f8046ebb03ef2b88802172fc893c3c21eec708d4cf417998e2f3198ac6ab731cafdc6357803a67837fe704f0cf97dbbccded29b3322731e3ef32306b1eeab50b6164ed8ca03c1dc54a7f3be21ce009f15e11c8f7781cdbe0f4a9dde33bd7c15cdd10a09fbe7387b73778da6e88d2f562e330bcd8e8e1d938ca5e707b95329f9d4166f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466093e1b1efe8e34b3e6a15ea71046d6d687e589bf6fd4190d5e72ce7637943702cf3901fc09d4cff81ef24d4e9f3a3dbe731d3cbf3605e8a7efdce1ed4d701c2a61de904166f57964cc86879f75c5ac79a8b74208236be784e589c7b115d1e065a8716c13f08418e703f5331ec7363b7d5ae1f19debe0f9b539403f7de70e6f6f86e3a0cccaec63363cfc8c6066cd43bd2e218cac6d0cca538abfdfd8150d5e861ac736034f88713e90eff138b6c5e95397c777ae83b9ba25403f7de70e6f6f81e35009f3860c32abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3fafccaf1d9f0f0b3ce99350ff5560a61646d53509ef6f8bac3ca68f032d475872dc0b339759ef2758700bec7d71dce75fab4d2e33bd7c1f3ebdc00fdf49d3bbc7d2e1c87e39d7943069935374687597343999398353794398959734399939835379439895973439993983537943989597343999398353794398959734399939835379439895973439993983537943989597343999398353794398959426e189e55b6ccac79a8b74a08236b9bc3f2c4cf3d58150d5e86ba6fe75ce0d912c09f40fd8cefdb39cfe9d32a8fef5c07cfaff302f4d377eef0f679701c9459997dcc8667b52d336b1eeaad16c2c8da96b03cf138b63a1abc0c358e9d073c21c6f940fd8cc7b1ad4e9f567b7ce73a98ab5b03f4d377eef0f656380ecaaccc3e66c3b3c69699350ff5d6086164eddcb03cf138b6261abc0c358e6d059e10e37ca07ec6e3d836a74f6b3cbe731dccd56d01fae93b77787b1b1c076556661fb3e1596bcbcc9a877a6b8530b2869f7f98edc5f478961580a50ada0a3586474edf79c17ce1a54518cf52613c7385f14c17c6334918cf78613c0b85f18c11c6334f18cf22613c3384f1d40be399208ca7248ca75a184fab309e26613cf385f1cc14c6335918cf62613c79613c35c2781608e399258c678a309e89c2786a85f11485f1340ae36916c6d3238c67b6309ea9c278ea84f18c15c6334718cf34613c05613ce384f1b409e3c909e0c947c75ee7c4eb276340e3eb196b413bdf967b40abf2b4c1fbd9061acf17f03ecc783376f2b1ed5579dadbe6e11a0d3fb1ad6ed8e6f6ea80639b109e36613ce384f11484f14c13c6334718cf58613c75c278a60ae3992d8ca747184fb3309e46613c45613cb5c278260ae399228c6796309e05c2786a84f1e485f12c16c6335918cf4c613cf385f13409e36915c6532d8ca7248c6782309e7a613c3384f12c12c6334f18cf18613c0b85f18c17c6334918cf74613c7385f12c15c6d3228ca7cac37341fa3cf177ca7aa2c1cb50d7642e08ec4fa07e16cd7e2fb4fb4af1bb2cf177d52e72bcea71bc2a409d0bc1bf8b02f897837679dfbccded29b33227311b1e9eebc5eba55caf5908236b5bc3f2c4e363733478196a7cbc0878028c636d81fa198f63db9d3e357b7ce73a98abdb03f4d377eef0f6764fdb0d51ba5e5c3c0c2f2ef6f05c3cca5e707b95325f984166093e1b1efeeccaac79a8b75408236b1784e589c7c7a5d1e065a8f1f162e009f1fe11a89ff1987089d3a7a51edfb90e9e5f9704e8a7efdce1ed4be03854c2bc3d83cceaf3c8980d0fcff9336b1eeae1f7c05e4e46d62e0aca538a7fa3b2291abc0c358e5d023c21c6f940bec7e3d8a54e9f9a3cbe731d3cbf2e0dd04fdfb9c3db97c2715066655666655666655666655666655666655666655666655666655666655666d9cc8687bfbbc7ac79a8d7288491b58b83f294af3b34468397a1ae3b5c0a3c21aecb04f23dbeee7099d3a7468fef5c0773f5b200fdf49d3bbc7d191c076556666556666556666556666556666556666556666556666556666556666596cd6c785a6c9959f350af4508236b9784e589bfb7d5120d5e86baee7019f084b82e13a89ff17587cb9d3eb5787ce73a98ab9707e8a7efdce1edcbe13828b332fb980d0f3f1b8d59f350af5508236b9706e5295f3f6d8d062f438d6397034f88713e90eff138b6c3e953abc777ae83b9ba23403f7de70e6fef80e35009f3f60c32abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3fafccaf1d9f0f06f9c316b1eea158530b27659509ef6f8ba43311abc0c75dd6107f084b82e13c8f7f8bac3154e9f8a1edfb90e9e5f5704e8a7efdce1ed2be0381cefccdb33c8acb9313acc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc1272c3f0b4717b769d877a6d421859bb3c2c4ffcdc83b668f032d47d3b5700cf8e00fe04ea677cdfce4ea74f6d1edfb90e9e5f3b03f4d377eef0f64e380e3b9559993dcc86a764cbcc9a877a25218caced08cb138f63a568f032d438b61378428cf381fa198f63bb9c3e953cbe731dccd55d01fae93b77789bdb5366654e62366def4ebfed783cc0b6d99fc8e1e16577602f02f5331e0ff6447e8fb9bd02d4c163be27403f73d02eef9bb7f7c071a884797b0699d5e791319bb6f7a6df763c1e60dbec4fe4f0f0b237b01781fa198f07bd91df636eaf0075304f7b03f43307edf2be79bb178e4325ccdb33c8ac3e8f8cd9b4bd2ff5b6cbcf49c3b6d99fc8e1e1655f602fc2f4b33c1e5c19f93de6f60a5007f3f4ca00fdcc41bbbc6fdebe128e83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66366d5f957adbe5f97b6c9bfd891c1e5eae0aec45987e96e7eff7477e8fb9bd02d4c163be3f403f73d02eef9bb7f7c3715066655666655666655666655666655666655666655666655666655666655666d9cca6edabd36f3bfe3e0eb6cdfe440e0f2f5707f622503fe3f9fb6b22bfc7dc5e01eae031bf26403f73d02eef9bb7af81e3a0cccaec63366d1f48bdedf2f53c6c9bfd891c1e5e0e04f6224c3fcbe3c1c1c8ef31b757803a78cc0f06e8670edae57df3f641380e95306fcf20b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfaf1c9f4ddb87526fbb3d9ebfc7b6d99fc8e1e1e550602fc2f4b33c7fdf17f93de6f60a5007f3b42f403f73d02eef9bb7fbe0381cefccdb33c8acb9313acc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc1272c3b47d38fdb6e3efb363dbec4fe4f0f07238b01781fa19dfff726de4f798db2b401dccd36b03f43307edf2be79fb5a380ecaaccc3e663c4fc6a5d7767c3f1cb75165d7463b62cb63403b6acbd5a0f5db720d68d7d9722d68d7dbf258d06e80feb076a32d2f06ed265b2e81f66a5bbe02b4d7d8f24ed05e6bcbbb407b9d2def06ed665bde03daeb6d792f68b7d8722f68b7daf23ed0de60cb5782f6465bbe0ab437d9f27ed0de6ccb5783f6165bbe06b4b7daf201d06eb3e583a0dd6ecb87407b9b2df78176872dcf07ed4e8ff6765bbe10b47778b4bb6c793c6877dbf204d0de09655ebfcb962782f66e5bae03ed3db65c00edbdb63c09b4f7d9723d68f7d8f264d0eeb5e529a0dd67cb5341bbdf96a781f6802d4f07ed415b9e01da43b63c13b4f7dbf22cd01eb6e5d9a03d62cb7340fb802dcf05ed83b63c0fb40fd9321ea30fdbf261d0781cb816341e078e80c6e3c051d0781ce8078dc781eb40e371e07ad0781cb80134ce9d1b41e3dcb90934ce9d5783c6b9f31ad038775e0b1ae7ceeb40e3dcb91934ce9dd783c6b9730b689c3bb782c6b9f306d03877de081ae7ce9b40e3dc7933689c3b6f018d73e7ada071eedc061ae7ceeda071eebc0d34ce9d3b403bc196ef04ed445b7e3b6827d9f23b406bb0e5bb403bd996ef06ed145bc67181c79f778176aa2dbf1bb405b6fc1ed016daf27b415b64cbef038ddf73ee01add196ef056d892ddf075a932ddf0fda525b7e00b4665b7e10b4165b7e08b4565b7e3f68455b7e18b4365b7e04347e9ffc0068edb6fc41d03a6cf943a02db3651e17ccf967ce19ee33fb5107fd6bf270b3360eb8bba3743f33715bbc6fde2e0223fbdd3afa8ca5e132b6388c86a714c033cc215e86fabf1f33189e36f87b5a3c81fa19ffdfafdde953d1e95301ea9c0afd6c0fd0cf1cb4cbfbe6ed76683bc431472f6aec7e17385e54439d27ed9b9c590de523efc3e46faba72fcb03f785f7cde3d2f25168bbc369bbd9691bc75e5e863abf3a8079590066b3dfcef4f71b9f5f2becbe38a7b89d66e853177890569fb0ed9c0d6e87f56a28bf503f5097ebb11ffcfec5ec2697f95822bbfbba92f3ba02d459eee97f77946eff3b1d9e4e87d91c93e7ea0738029c0f710e2c773878bb19bceb4cf06e3978c775f0fdaf259077cb1c1ede6e011efe8cd30e1a7f56c03908fe7bd32870bbe35ebb879bb50e606cf13036a7cf187fd669711879bb1918595b063c1d813c738ff502c71f7c5fae75eaf06baba1ceffc07b63de53d79c77ff817ef1ff995f8cd21dd36b03f885ff9f8fc09fc8f13002bfb89f350178264403ffa73fdadf7764d795bd5b7b77edcd015ab58389eb9ca71b55a061798c478ba2c1531738e5c9531738e559e5d88253265cdffc57ca748ba7077a0feeefbfe050efa13d476e3adcdfbb7763df95485de3d02369520f9014355f8f86a21f1f1d7bf0533d33196e3eec3f6741c6d84ed4582063dfb868c03e9ed931efd66644313335e68c343331c65a33d3626656cc4c8a99393133256666c4cc8498990f33d3616636cc4c8699b93033150d517926e214e0f931309aff2198b3ddcc24989903335360de25cca74f33b29a4f12669433a39b7917339f92cdff98ccc861466533e29851c2bceb99773bf3e9c4bc5bafa45845b19a620dc55a8a75d6eb1e8ad3284ea73883e2551467529c457136c57a8a732836506ca4d844b199620bc5b914e7516ca5d846713ec5055179e6efa2a87c85f3628a4b282ea5b88ce2728a1d5179467d67549e313733e46646dccc809b196f33c36d66b4cd0cb699b13633d4d744e5196833e36c6698cd8cb2994d34b38766b6d0cc0e9ad94033fb6766fbccec9e99cd33b37766b6ceccce99d93833fb6666dbccecda2d5179f6cccc9699d931331b6666bfcc6c9799dd32b35966f6cacc56dd119567a3ccec93996d32b34b6636c9cc1e99d922333b646683ccec8f99ed31b33b6636c7ccde98d91a333b636663ccec8b996d31b32b8f44e5d913335b626647cc6cc847283e4af1318a8f537c82e293149fa2f834c5a3149fa1f82cc5e7283e4ff1058a2f527c89e2cb145fa1f82ac5d728be4ef118c53728be49f12d8a6f537c87e2bb14dfa3f83ec50f287e48f1a3a89c933fa1f829c5e3143fa3f839c52f287e49f12b8a27289ea4f835c55314bfa1f82dc5ef289ea67886e2f714cf523c47f1078ae729fe48f1278a3f53fc85e2af147fa3f83bc53f285ea0f827c5bf28fe1d0dcca4e240f198dde059bd5dfdfdbd070ff737f4f7351cbcee40fffec3076e6ab8617fff550d7dd7f71ed977a0ef067cf1d57618e229cb9e234776ddd4b0ffd0dede1b1bfaaeeb6fe8dbd7b0bbefba437b8fe28b6eb32f9a776c8bbbf6ee4d6eecdeaa9740fae0081bfd847d1d4f06af1fba6f9f1e89215f18c98b9e1e618736d97791d5767b5bf99dbae1e881befe8662c321fa77d7017a4defde9606fcdb5132f9687fc3d1fe5d47fa1bf61de93bd8d0d682fbbda776049d78a27e042ffaeffae1f73cfa3fac10a5ab91130300", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000047641f8b08000000000000ffed9d77781447baee5b20e22001ced9c2f6ae033616424409189c73c6c618631002830d88689c713639384772cec1648c0163eccdd9bbeb0db677d71bce7dee73ef9fe79c7b8fefed9aa9efe8a5a81e3472d7f04a53fd3ca5a9fe54dddfafdefeba3a55771504e9e95f612ad0f9a661ba20387a92ff27f56fe9779b3ac7b8ae52979c050d84b34903e16cda40380b1b0867b306c2d9bc8170b668209c2d1b0867ab18390b80cf156feb06c69b6860bc6d828611b7450d84b3b88170b66d209ced1a0867fb06c2794203e13cb181709ed440384f6e209ca73410ce531b08e7690d84f3f406c2794603e13cb381709ed54038cf6e209ce73410ce731b08674903e1ecd04038cf6b209ce7c7c8d91138e55efef7f4eff7f5ef85faf722fd7bb1febd44ff76d4752cd4f39786e9b230750ad3e5c6ff9430ea867e5998ba18ff2b0f53d730750b5377fdbf12fdbf1e61ea19a65e61aa085365987a87a94f98fa6a3dfa85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bbc2d43f4c7787e91e83654098ee0dd3c030dd17a64161ba3f4c83c3f440988684696898aac2342c4cd5611a1ea611617a304c23c3342a4c0f85e9e1308d0ed398308d0d534d98c685697c98268469629826856972981e09d31443b347c3f458981e0fd31306e793617a2a4c4f87696a989e09d3b3617a2e4ccf87e98530bd18a697c2f47298a685697a9866846966986685697698e684696e98e685697e985e09d3ab617a2d4caf87e98d30bd19a6b7c2f47698de09d3bb9a457684f7c2f47e98168469619816856971989684696998968569799856846965985685697598d684696d98d685697d9836846963983685697398b684696b983e08d3b6306d0fd38e30ed0cd3ae30ed0ed39e30ed0dd38761da17a68fc2b43f4c07c274304c1f87e950983e09d3e1307d1aa6cfc2f48330fd304c3f3234ff71987e12a69f86e967daf673fdfb0b5d56f6f95feadf5fe9df5febdfdfe8dfcf8df2bf35e67f67ccff5eff7ea17fffa07fffa87fffa47fffac7fbfd4bf5fe9dfaff5ef5ff4ef5ff5efdff4ef37faf7effaf71ffaf79ffa573dff7bb5433adf32a89d92414c6d52f9f0a1eafebf886d3e5f54cfae9aeaffc96f89b617ea79f92dd0f6667abe99616faee79b1beb69a9e75b1af6623d5f6cd8dbe9f97686fd043d7f82613f49cf9f64d83be8f90e604fe8ffa52b96fe51b6a6da54003689cf26606ba66d4dc1d65c5607b616dad60c6cb27d9b83ad95b6b5005b6b6d6b09b684b6b5122dc3d446db92415cb1523a54adb728eef5ea6726c5f1f356a9f5b675c4db2e7ede616abded1df0aaf83841afab08e2e6446d2b06db49dad6166c276b5b3bb09da26dedc176aab69d00b6d3b4ed44b09dae6d2781ed0c6d3b196c676adb29603b4bdb4e05dbd9da761ad8ced1b6d3c176aeb69d01b6126d3b136cbac90dce02db79da7636d8ced7b673c07681b69d0b3639c72b019b9cef75009b9cfb9d0736390f3c5fdb54dbd1aa00fc69bbb45b297fd26683edfbd25e83ed4269abc17691b4d360bb187c8bed12686bc4d651dba4dd52ffeba5f3c920aefda42cb59f54c4bdde70cd6abdbde35f6feaf95d9fa056eb24f8a900adfaea7c8c7d5b3aa36f39b7113f622f84fc0d5056ca891e72ec1176752ca8d4f9be1996eb652c570c652a2df54f06f1d6bfb7c1d3db606e06793731dba5d4c76c9da7ac6376009435634fce831a63ccde0c1c0e62b6dcc76c9da7ac6376049435634fce851b63ccde071c0e62b6879b982d2bf5319bbe371604f6d893eba1c618b3a38023fe98edea63b6ee53d631fb1c9435634fae891b63cc4e018ef863b67b0f7f6e50e729eb989d0765cdd893fb338d31665f040e07313bccb7b3759eb28ed90550d68c3db957d81863f655e0883f667b3a8ad92e3e6683f473ce20b0c79edcb76e8c31bb1838e28fd961fefe6cdda7ac6376379435634f9ea134c698dda8f3ea39c3cff57386b3c0f60b6d3b1b78e38fedea3247b1ddd9c776baff4710d863549ee735c6d8fe48e7551cff0afa2388edd7d257016cbfd1b6f3c0f6b9b69d0ff572b00f74f7fb40ddeb94ed3ef047286bc6b23c5b6e8cfbc02f80c341ccf6f0315bf73a651bb3ff0665cdd8937e0e8d3166bf040e0731dbd3c76cddeb946dccfe3b943563ef229d6f8c31fb3f755e9d2f7ca1cf172e01db1fb4ad23d8fea86d9782ed4fda7619d8feac6d9dc0f6a5b65d0eb6afb4ad146c5f6b5b67b0fd45dbcac0f6576deb02b6bf695b39d8bed1b6ae60fbbbb67503db3fb4ad3bd8fea96d3dc0f62f6deba96daa9f9ef4bd3aac6d2d813f19c4bb6da5dfa5ac5be63be7c0775bc377db1cfa6e6ff86e6ff15de6c077027cc85460cc27215fe696a7b41878d05779fcbebaa8ba7709ea5ef772e0e9eaa0ee09f051179eaec0d32d7e9ed4f1b37bfceb4d6de32e86a609f0d505ead5c341bd0ac097ac5be6c55f31d8b06ded6161ec193f635901f89275cb7c4f60141bb6f5f22e95ec3fea787861412daf837d29754e24fee4db55c2510e76297371875ab68e9aad08fe8fc7bd6e86cd515ca6e2427cc9ba655efc15417dbae59eb1acae8c5d0d46576d4401f892757bdfb5db41f2781c7771ad636bd3c477450e7cf7347c971bbeb1ed9429d3b1ad2730c77ecda98f6d95f1afb714af4fe4da50fce0f9035ec3c55527f42dd786e247ec8590bfa5a0b6ac94133da41d167615cbb22d91dd5cae87b15c3194a9b0d43f19c45bff4a83a7d26056dbe44a38163ad81f5231506170c87c39685719a15d056827652e02ed5cb567bd0c1e99ef063cd28e75071e57d744513cb9b81e3b966f3c87c5eb67f93f9e07b8da5e9d0d4699b76daf9ec0683b5771703d93f15ca52b308aad17f07471a459d476ed42e2db41aca4da23f121e7e6b2ff7603bb94e9a95fa8536de543d056ba88118c4799ea7acd1bff762a4b5d8377cd8207b79d83ebaace8ee2b114efdf7c1bc41b6b66bbd4d5d02aea1e8fabb6bc8bc123f3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f333e4fc27e5b52ae1b09a3d9ffcdd57dfed4370cf5ba64fdeab9ceff71da1facac14fbc7483f884b8c3a174299a226b565ff1ff407339f53611fc96e6eb54b6d4bec8f998479f1877dad705b32f4772a89cd77fa5b942e9eb7a93ed6ea3b9a66dfcf6e164d5df47f464d0b0c4db13ffea5068f8ad3caa6b56c2e9efd65fb2c12b5927c9ccff68a037bacc7bf5dca8e7866dd2438b2fdc0e38cabfe3bd256cbf3f20ac377219439b349edb691be5532ce6c176339ecf723eb96652e017ba5b1ee767a59e16866acbf3b2c2b65ce8136f540935acd1cb49565d9f65dc7e7e6f11f87d3cff1bb64c1d319785cb4338ece378ef8de6adccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c8431477d1f52cf33e45b65b2fed4f7829bd4fa75fd1c4e9e397534ea8cef8efeef26b565b7ea7c5170747f87a86de9eafb1451db52fce1b767f059908be7ba05e04bd65d66d142f225b1f92e733636843cc7ef62e85a6ed1d4d5fe8acf585153dc5fbb1a3cf86c34eadb3e6586cd65dfa1a8b8107fb82f95814df2f87eb48bed8cc712b35f8ff8c3e7d73fd2dab60b5c6dfbb25297ed067e3725191c1ddff83d959f43dbf74b9dc73e1cd877e46bcbff65caf49c5af4537576f07dcdd20258976c5fdbb73dfb016b4cbe3be3ba0a74ea67685008f9af9ad49695725256b41676b58fc8376090dd5caeabb15c3194e963a97f3288b7fee6b756fb1acc6a9bfc06e2ec6b38febb6a93fa446874096824651c7fb3d1dabfd2ec5788ed6873a38c2c8bdfa2fb17b45151fd476dc700d7c73159b7ed38661e17ead2cf33dffb69fd07b41771f7d3fa0f8821eca71518ebef08eb17aee641f4b145cafc97b17ef39c5c96c17e60ffbd9fc0f75cca743e9b73f2e3757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c6badb56cb3ca08ee9e96658b229615adcc6f85150547ebe7e63b6be97dbeaf5117896bfc06b9943911eae2e6bc257d0ee8ea9b7249a893ca9759ea2a654e837ded0c9d4fc076c2fdf662cbff65ca740e8863b85f117f9d53dbf74ae04c821ff47d15b0c6e4bb33fa967340f123f642c85fd4b4b6ac94133d446b6157fb889c4721bbb95c85b15c3194e967a97f3288b7fe57183c5718cc6a9b9c0d717631f44377d556f78bd0a823682465f09ea2ed3ba0b67b1daededf883a97c2f797ccf32b3c4eba396fb29fc79af7d56ce7081d0d7e3c47e80eed6cc252d6bc5f28c7cb38fb0de3bb12ddc12fbe2be1eadbcdbd40b724cce379c1f1f4ede23bb6ca5fd49809bd72e03b6acc845cf86e6ff86e9f43df5e73af3993e60ec62048bd7f86df2c5553a6f3521c9740966b028c2ec6724804477e7bfc588c38be832cd714185d1c1fb2fdf679776094e50a81d1c5bba538fe465d18f11bc3789c174607df8aed5cdf6fc5e23dbde6c0c8f4ce263e9b6a018c2ece8bebfbae1e9ecfb7845f57e31275c982b10c1865b956c0e8e2de385ecbd48511af8b64b9d6c0e8e21956b6e33be1b7e7f1deb24bc64cc776c77d51cab2bdf752e99627e3b906fa7630ae614a0bbccf782c2d7abbe5c978ee83be1ddcf74b6981e30c1e4b0b7c36e862dcc34470e473b863f1e0f34b59ee04604c3a62ec9b05631218fffb5e3130f673c498cc82b11f308afd24607470ff35c5d82f0b46bc4f29cb9d0c8c573a62bc220bc62b8151963b05185ddc4b4d80dfba305e058cb2dca9c078b523c6abb260bc1a1865b9d380f11a478c5767c1780d30ca72a703e3b58e18afc982f15a6094e5ce00c6eb1c315e9b05e375c028cb9d098cd73b62bc2e0bc6eb8151963b0b186f70c4787d168c3700a32c773630dee888f1862c186f044659ee1c60bcc911e38d5930de048cb2dcb9c078b323c69bb260bc191865b91260bcc511e3cd5930de028cb25c0760bcd511e32d5930de0a8cb2dc79c0789b23c65bb360bc0d1865b9f381f176478cb765c1783b30ca721700e31d8e186fcf82f10e6094e5be078c773a62bc230bc63b815196fb3e30dee588f1ce2c18ef02c63b2d8cfd1d31de9505637f6094e52e05c6bbe3674c5d4bf7cf82f16ee0b9277e9e94667767c1738f5b9ed477f5eeb6f8ba377e5fa96d3120a87bddef059e81f1f3a4b6c5bd59f00843312c879add173f634ab3815930de073c83e2e74969765f163c8340b3fb2c9add1f3f634ab3415930de0f3c83e3e74969767f163c8341b3fb2d9a3d103f634ab3c159303e003c43e2e74969f640163c43825acd1eb06836347ec6946643b2601c0a3c55f1f3a4341b9a054f156836d4a2d9b0f819539a5565c1380c78aae3e74969362c0b9e6ad06c9845b3e1f133a634abce827138f08c889f27a5d9f02c78468066c32d9a3d183f634ab31159303e083c23e3e74969f660163c2341b3072d9a8d8a9f31a5d9c82c184701cf43f1f3a4341b9505cf43a0d9288b660f3b627c280bc6872d3c717f27fb218baf318eea3e3aa87bdd85a11896c37e12631d318ec982712c30ca72d84fa2c611e3d82c186b8051964b3866ccd44fa2067c8f8bdf77aa5daa09eaaecf38b73c19fb49a0eff18eb41817d45d8bf16e7932f69340df131c69313ea8bb16138067a2032d12e0a32e3cc2500ccb613f89498e182766c13809186539ec2731d911e3a42c182703a32c87fd241e71c438390bc647805196c37e12531c313e9205e3146094e5b09fc4a38e18a764c1f82830ca72d84fe231478c8f66c1f81830ca72d84fe271478c8f65c1f83830ca72d84fe209478c8f67c1f80430ca72d84fe249478c4f64c1f82430ca72d84fe229478c4f66c1f81430ca72d84fe269478c4f65c1f83430ca72d84f62aa23c6a7b3609c0a8cb21cf69378c611e3d42c189f0146590efb493ceb88f1992c189f054659ee61c78c99ae5f9e6de4bea3ae551abbefa8eb92c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3fe7c077027cc85460cc27212f0cc5b0dcc39eb15133224f497c3ca55877f4f53c41dd9fb7f01438aa3bfa7a81a0eec2d0d0189f6b008c0f370046af63ba0f627d1815cf8bf0ff648c3c2f64c1f322f0bce488e7c52c785e029e97e3e749c5d44b59f00843312cf77003607cae01307a1dbd8e4c8c5ec7fcd1d1337a46cfe8198f07634368c33d638388c7b2fa322a9e69f1f3a4347b390b9e69a0992c778f5bc6b2fa322a9ee9f1f3a4349b9605cf74d06c9a4533078c65f565543c33e2e74969363d0b9e19a0d9748b660e18cbeacba87866c6cf93d26c46163c3341b31916cd1c3096d59751f1cc8a9f27a5d9cc2c78668166332d9a39602cab2fa3e2991d3f4f4ab35959f0cc06cd66593473c058565f46c533277e9e9466b3b3e099039acdb668e680b1acbe8c8a676efc3c29cde664c13317349b63d1cc0163597d1915cfbcf879529acdcd82671e6836d7a2192be3c30d80f1b906c0e858c7b2fa322a9ef98e78e665c1331f785e71c4333f0b9e5780e7d5f8795231f54a163cc2500ccb3ddc00189f6b008c5e47af2313a3d7317f74f48c9ed13366c7f87c0360f4dbda33b2323ab8becaf80ecd2b8ddc77d43b348ddd77d43b348dddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97e2d7edf65d97e63e635e071f1cd1b47f52c55eb7d5dafebdb18f5535abd6168f58aa1553194791df47bc3817e05e057d62df3e22f5be60b09981df92e53ed4b2ba8bff878ced043f97fd351dda3dafa371bb9efa8b6beb1fb8e6aeb1bbb6f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7316df986f16d49eb7cbf74fd53aded2f9423d2fe59f07bb9499d822fddb2ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff57e680273078820c3cf3c8782693f1cc24e31949c633888ce756329e2bc9789e24e32927e31947c6338c8ce76e329e1bc8782e27e3e943c633858ca72719cf2c329e87c8785e22e3194cc6733b19cfd5643c4f93f19491f14c20e3194ec6732f19cf4d643c49329ec7c878ba93f15c4cc633868c673619cf45643c43c8785e26e3b9938ca7988ca72d19cfb5643c2f90f15c46c65341c6f30c19cf5c329e49643c0f92f1dc47c6534ac6730b194f27329e2bc8789e20e3e94ac633878ca7868c671a194f15194f7f329e4bc878ae27e3694ac6d39b8c673e19cf23643cbdc8784691f17424e3b99f8ce736329eabc8789e22e3e942c6339e8c673a194f3519cf00329e1bc978fa92f13c4ac6d3838c673419cf85643c0f90f1dc41c6938bef9966c3d3868ca7888ce71a329e67c978a692f17426e39948c633838c670419cf40329e9bc978fa91f13c4ec6d38d8c672c19cf50329ebbc8785e24e36947c6d39e8ce73a329e02029e4470f4182609f8ff6b606b622cab3efb3aba43edffdfd6f626b0cc3b3adfd4b2eeb7c126df927dc7b22ceaf436d425a9f3a5df6d4ae984be92302ffe8a80e31d129eebc878da93f1b423e379918ce72e329ea1643c63c978ba91f13c4ec6d38f8ce766329e81643c23c8786690f14c24e3e94cc633958ce759329e6bc8788ac878da90f1bc46c6730719cf03643c1792f18c26e3e941c6f328194f5f329e1bc9780690f15493f14c27e3194fc6d3858ce729329eabc8786e23e3b99f8ca72319cf28329e5e643c8f90f1cc27e3e94dc6d3948ce77a329e4bc878fa93f15491f14c23e3a921e39943c6d3958ce709329e2bc8783a91f1dc42c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643c1791f1cc26e31943c67331194f77329ec7c87892643c3791f1dc4bc6339c8c6702194f1919cfd3643c5793f1dc4ec633988ce725329e87c8786691f1f424e39942c6d3878ce772329e1bc878ee26e31946c6338e8ca79c8ce749329e2bc9786e25e31944c633928c672619cf64329e79643c95169ed71cf1c8fbeeb26e997f8dc4b783ed50aad6fbaea33abda7d7d54caf57f8c55f219499da3afdabde0fc76585cbfc3e01be9bf31e68f49ea3bac8f62830b60ffa7ecb916f79474bd62df36f3572df6d0ddf6df3c4777bc377fb3cf1ede3dcc7793ef8f671eee33c1f7cfb38f771cee4dbc1b541197e274da602633e0979bc5e70f17d3947f53ce23af1db18f5535abd6f68655e5b1543997741bff71de867bbf69479f1972df38504cc18172541bc71b120fe3a95a976ab15e8bac0d017ebb5d091a651c790858ddc77d431a4b1fb8e3a863476df3ece7d9ce7836f1fe73ecef3c1b78f731fe74cbe17e97c8cd78da5e8433d5f94eb8145e07789ce17c4e857ad6bb15e57a15eb7702c01bb94f94f78aee9f779bfcfc7e5db1fdb7c9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8668e73332ffdc52f023657fdf9a3623117ef121c4fdf51b1d8d87d47c56263f7ede3dcc73993efa50e7c27c0874c99faf82d059ec50e781cd533f56c639951a7d78c3a1543193cc62f7350cf02f02beb96f965c0235325f0b88883ba6c73e49947c633998c672619cf48329e41643cb792f15c49c6f324194f3919cf38329e61643c7793f1dc40c67339194f1f329e29643c3dc9786691f13c44c6f31219cf60329edbc978ae26e3799a8ca78c8c670219cf70329e7bc9786e22e34992f13c46c6d39d8ce762329e31643cb3c9788690f1bc4cc67327194f31194f5b329e6bc9785e20e3b98c8ca7828ce719329eb9643c93c8781e24e3b98f8ca7948c672119cf2d643c9dc878ae20e379828ca72b19cf1c329e1a329e69643c55643cfdc9782e21e3b99e8ca729194f6f329ef9643c8f90f1f422e31945c6d3918ce77e329edbc878ae22e3798a8ca70b19cf78329ee9643cd5643c03c878de27e3b9918ca72f19cfa3643c3dc8784693f15c48c6f30019cf1d643c6dc8788ac878ae21e379968c672a194f67329e89643c33c8784690f10c24e3b9998ca71f19cfe3643cddc878c692f10c25e3b98b8ce745329e76643cedc978ae23e32920e0490447bffb9f80ffbf0f367947fd35b02dd7f9c5606b62f1d154e79781ad50e7651d2dc234a5c3d1eb469d5cbd978fbe92302ffe8a80633909cf75643cedc978da91f1bc48c6731719cf50329eb1643cddc8781e27e3e947c6733319cf40329e11643c33c8782692f17426e3994ac6f32c19cf35643c45643c6dc878ee20e379808ce742329ed1643c3dc8781e25e3e94bc6732319cffb643c03c878aac978a693f18c27e3e942c6f31419cf55643cb791f1dc4fc6d3918c6714194f2f329e47c878e693f1f426e3694ac6733d19cf25643cfdc978aac878a691f1d490f1cc21e3e94ac6f30419cf15643c9dc8786e21e35948c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643cb3c978c690f15c4cc6d39d8ce731329e2419cf4d643cf792f10c27e39940c65346c6f33419cfd5643cb793f10c26e379898ce721329e59643c3dc978a690f1f421e3b99c8ce706329ebbc9788691f18c23e32927e379928ce74a329e5bc9780691f18c24e39949c633998c671e194f658e78d4bbedd2d73a002e9c92905f063c0b1df038aa67297ed7e0db18d7abb45a6168f5bea1553194590afaad70a05f01f89575cbfc0ae07956e76ddf54789684516c0b1df324a0ce3265da0756008f8b7dd2513d53b1bad2a8d3b316dda50cc6ea4a07f5b4ed3b32bf12785ed079614d40b9174818c5b6cc314f02ea2c53a6585d093c2ef61d47f54cc5ea2aa34e2f5874973218abab1cd4d3b6efc8fc2ae07951e7853501e55e246114db0ab73ce509a8b34c99627515f0b8d8771cd53315abab8d3abd68d15dca60acae76504fdbbe23f3ab613b7866cf6c63563c72ff5e581350ee251246b1ad74ca535e9a803acb94a91d5b0d3c2eda7947baa7dab135469d5eb2e82e653056d738a8a76ddf91f93516df2541bc5aacad83166b2d3c6b73ac85f8cb9679690364f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e6266d059f1c8f709853501e55e266114db2ab73ca9f7825e0e8e9c0a8cf924e4d702cf6a07fa38aa67aa0ff93aa34e2f5b749732b87fad73504fdbbe23f3eb603b64c3bca601327b9debc7ac78a6e9bcb026a0dc341246b1ad76cb936ac7a605474e99dab175c0e3a29d7754cf543bb6dea8d3348bee5206f7aff50eea69db77647e3d6c07cfec996dcc8a67bace0b6b02ca4d276114db5aa73c65a9f71ba707474e99dab1f5c0e3a29d77a47baa1ddb60d469ba45772983b1bac1413d6dfb8ecc6f80ed900df39a06c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9df34767c53343e7853501e56690308a6d9d539e2ea9e70e338223a74ccf1d36008f8be7328e744f3d77d868d4698645772983fbd74607f5b4ed3b32bf11b64363675ed300997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1ccd479614d40b999248c625bef9627f5dd8399c19153a67e3b1b816783037d1cd533d56f679351a79916dda50cee5f9b1cd4d3b6efc8fc26d80e9ed933db9815cf2c9d17d604949b45c228b60d6e7952edd8ace0c829533bb609785cb4f38eea996ac7361b759a65d15dca60ac6e76504fdbbe23f39b613b7866cf6c63563cb3755e5813506e3609a3d836bae549b563b38323a74cedd866e071d1ce3baa67aa1ddb62d469b645772983b1bac5413d6dfb8ecc6f81ede0993db38d59f1ccd179614d40b939248c62dbe4982701759629533bb605785cb4f38eea996ac7b61a759a63d15dca60ac6e75504fdbbe23f35b8167aece0b6b02cacd256114db66c73c09a8b34c9962752bf0b8d8771cd53315ab1f18759a6bd15dca60ac7ee0a09eb67d47e63f009e793a2fac0928378f84516c5b1cf324a0ce32658ad50f80c7c5bee3a89ea958dd66d4699e45772983b1bacd413d6dfb8ecc6f039ef93a2fac0928379f84516cd88ecd77c45364f01459b4385ebe9516153adf46ff26e0ff15c0e8aa6d996f30ca3cc6b8d88a72a0595b83a7ada1d9f1f4adb4a884bc9a707b550223c3f66a9b03cdda1b3ced0dcd8ea76fa5456f9d6fa77f717bf5064686edd51e781cb4cfe50983474d998edddb1cebe3a89ea963f7f6c0ae3b1e87a40c1ebbb73ba8a7ed5c42e6b7c376f0cc9ed9c6ac78faebbcb026a05c7f1246b1e139ff8ef879ca13068f9a32b5633b1cebe3a89ea9766c6760d77d07e82e653056773aa86701f89575cbfc4ed80ed930af6980cc5ee7fa312b9e013a2fac0928378084516cdb816757fc3ce50983474d99dab15d8ef57154cf543bb63bb0ebbe0b749732b87fed7650cf02f02beb96f9ddb01db2615ed30099bdcef563563c03755e5813506e2009a3d87602cf9ed879d263be208f9a32b5637b1cebe3a69ee9766c6f60d77d0fe82e6570ffdaeba09e05e057d62df37b613b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563c83745e5813506e1009a3d87603cf87b1f3a49f3b208f9a323d77f8d0b13e6eea997eeeb02fb0ebfe21e82e653056f739a86701f89575cbfc3ed80e9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99b99915cf609d17d604941b4cc228b6bdc0f351fc3ce50983474d999e3b7ce4581f47f54c3d77d81fd875ff0874973218abfb1dd4b300fccaba657e3f6c87fd9ed9335b9815cf109d17d604941b42c228b67dc07320769ef4f353e45153a676ec80637ddcd433dd8e1d0cecba1f00dda50cc6ea4107f52c00bfb26e993f08db211be6350d90d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63ae78fce8aa74ae7853501e5aa4818c5b61f783e8e9da74b69c2e0515381319f84fcc78ef57153cff4738743815df78f41772983fbd72107f52c00bfb26e993f04dba1b133af6980cc3e3672c3ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc0cb1a178aa755e581350ae9a84516c0781e793f879ca13068f9a0a8cf924e43f71ac8fa37aa6faed1c0eecba7f02ba4b19dcbf0e3ba86701f89575cbfc61d80e9ed933db9815cf089d17d604941b41c228b643c0f3a9039e84c1a3a64cedd8a78ef57154cf543bf65960d7fd53d05dca60ac7ee6a09e05e057d62df39f01cf489d17d604941b49c228b6c3c0e32256154f91c123f39f12f8565ad4e87c1bfd8bdbab061819b657510e346b6bf0b435343b9ebe9516e320af26dc5ee38091617bb5cd8166ed0d9ef68666c7d3b7d262bcceb7d3bfb8bdc60323c3f66a9f03cd8e677b783cf7ede319a75ef3e3a779c171d4bce0386a5ee035a7d2dcc1f1a50c8f650130e09484fc67c0f3c3f87952f7b83ecb82e787c0f383f8793a3baa67a95aef8f803daef52aad7e6c68f599a155319441861f3bd0af00fccaba655efc7966cf1cc58ce7b6c29a80729f92308aed07c0e3a2dd5075bf4caf4bd6df2c4cfb4eaaf5ebe2d903de776da6d72b1ce2af10cadc5e525bf6a0662b82ffcb7653f53964d81cbd0fdcd9f60c4ce6c55f5190bbfba099eecba2162e9edd647bdc3f64e1f9363e9e52dccfd1d7414775cfe639da410b4f8c75ef1cf50cf140fc754fb51f9df4ba64fd6a1ffdfc24a79a97e3be27ed4727a3ce8550e6b292dab25f40fb616b2b5cef9b724e6eee9b4d82daf64cb84ab4dd7cbef2adb64bb94fa03cb63915fa17f7cf0aa8abab7631ea1e13b68b66dbed527bf3199fe9bb1874f9845433db730ad4b1d2c25d49c08df198cbfd4cd66d7b465669e8c8a6196eeb4f2c3af6b670f726e066dcaf7b1b3ab26976acfdbabf85bb3f0137e37edddfd0914db363edd7032cdc0308b819f7eb01868e6c9a1d6bbf1e68e11e48c0cdb85f0f347464d3ec58fbf5200bf720026ec6fd7a90a1239b66c7daaf075bb807137033eed7830d1dd9343bd67e3dc4c23d84809b71bf1e121ca9239b66c7daafab2cdc5504dc8cfb7595a1239b66c7daafab2ddcd504dc8cfb75b5a1239b66c7daaf4758b847107033eed7230c1dd9343bd67e3dd2c23d92809b71bfae6bbf7dd6fdbac6c25d43c0cdb85fd7183ab26976acfd7a9c857b1c0137e37e3dced0914db363edd7e32ddce309b819f7ebf1868e6c9ad9f66b47efe59565fb9ee061a7faa4c76b3e9c05cfc7c0e322a61cc541a9a37e2ea9bea9070cad0e1b5ae1381807413f077d6132bedf2ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f333e3370ef1f98a94fb8484516cf84ccac57d7e55f7cbf5ba64fdcdc2d4f9945abf0763f75b565a60f84b0287f82b8432ff794e6dd9ae9aad28387abbe1b8d6b82df7c75e87f4b634e35fe6c55f11d4e700f038783f3fc573d0e03968d102df3b8dc777d930371a9795aaefefb40a6ab7f37ea33ea8e947b1fb3f52d30243d38f1cfb4e04476e4f61c0290979e471f16cd8513d536dc13ea34ea6c6c550e642a8e73e07f52c00bfb26e99df073c3235011e573118183c81451f992ac9782693f18c24e3b9808c671019cf69643cb792f1b422e3b9928ce749329e72329e71643cc3c878ce25e3b99b8ce744329e1bc8782e27e32924e3e943c633858ca72719cf43643cdf27e3194cc6732919cf19643cb793f124c878ae26e3799a8ca78c8c670219cf70329e0e643cf792f19c4cc67313194f73329e2419cf63643cddc9782e26e31943c6731119cf10329eb3c878ee24e32926e3694bc6732d19cf33643c15643c9791f14c22e379908ce77c329efbc8784ac9784e25e3b9858ca71319cf15643c2dc9789e20e3e94ac65343c65345c6730e194f7f329e4bc8784e20e3b99e8ca729194f6f329e47c8787a91f18c22e3e948c6f33d329efbc9784e27e3b98d8ca73519cf55643c07c8789e22e3e942c6339e8ca79a8ce710194f0919cf00329e93c8786e24e36946c6d3978ce751329e1e643ca3c9782e24e379808ce74c329e3bc878da90f11491f15c43c633958ca73319cf44329e11643ce791f10c24e339858ce766329e16643cfdc8781e27e3e946c633968c672819cfd9643c7791f1b423e3694fc6731d194f01014f2238fa5b4c09f8ff41b0c937833e065b13cbfae439b59457c7c5673b1cbdee2696757f6461409d3e84ba2475bef4bb4d299dd05712e6c55f11707c44c2731d194f7b329e76643c7791f19c4dc633948c672c194f37329ec7c978fa91f1b420e3b9998ce714329e81643ce791f18c20e39948c6d3998c672a19cf35643c45643c6dc878ee20e339938ce701329e0bc9784693f1f420e379948ca72f194f33329e1bc9784e22e31940c65342c673888ca79a8c673c194f17329ea7c8780e90f15c45c6d39a8ce736329ed3c978ee27e3f91e194f47329e51643cbdc8781e21e3e94dc6d3948ce77a329e13c8782e21e3e94fc6730e194f15194f0d194f57329e27c8785a92f15c41c6d3898ce716329e53c9784ac978ee23e3399f8ce741329e49643c9791f15490f13c43c6732d194f5b329e62329e3bc978ce22e31942c6731119cf18329e8bc978ba93f13c46c69324e3694ec6731319cfc9643cf792f17420e3194ec633818ca78c8ce769329eabc97812643cb793f19c41c6732919cf60329eef93f13c44c6d3938c670a194f1f329e42329ecbc9786e20e339918ce76e329e73c9788691f18c23e32927e379928ce74a329e56643cb792f19c46c633888ce702329e91643c93c9782ac9789a183cf87ff56ed8019d976f0715c2ffefd69dcbdbe97549197946acee55ec356caabe7b1cd5776f503b25617e0fd457d8f702cf5e473c1f1a3ca6ef22c8578266bb0d9b62dce58871b7c128f3bb8051f4db0d3cbb1df1ec31784cdf4590ef0d9aed346c8a718723c69d06a3ccef0046d16f27f0ec74c4b3cbe0317d1741be3f68b6ddb029c66d8e18b71b8c32bf0d1845bfedc0b3dd11cf0e83c7f45d04f901a0d907864d316e75c4f881c128f35b8151f4fb00783e70c4b3cde0317d17417e2068b6c5b029c6cd8e18b7188c32bf191845bf2dc0b3c511cf5683c7f45d04f941a0d926c3a618373a62dc6430cafc466014fd3601cf26473c9b0d1ed37711e40783661b0c9b625cef887183c128f3eb8151f4db003c1b1cf16c34784cdf45901f029aad336c8a71ad23c67506a3ccaf0546d16f1df0ac73c4b3dee0317d1741be0a345b63d814e36a478c6b0c46995f0d8ca2df1ae059e38867adc163fa2e827c3568b6cab029c6958e1857198c32bf121845bf55c0b3ca11cf6a83c7f45d04f911a0d90ac3a618973b625c6130cafc726014fd5600cf0a473c2b0d1ed37711e4478266cb0c9b625cea887199c128f34b8151f45b063ccb1cf12c37784cdf4590af01cd961836c5b8d811e3128351e61703a3e8b704789638e2596af098be8b203f0e345b64d814e342478c8b0c46995f088ca2df22e059e48867b1c163fa2e82fc78d06c8161538cef3b625c6030cafcfbc028fa2d009e058e78161a3ca6ef22c8df0936e1ed05b6f774be27d8ded5f91e607b47e7bb83ed6d9def06b6b774be2bd8ded4f972b0bda1f35dc0f6bace9781ed359def0cb65775be0fd85ed1f9be609baff349b0cdd3f97e609babf357806d8ece5f09b6d93a7f15d866e9fcd5609ba9f3d7806d86ce5f0bb6e93a7f1dd8a6e9fcf5607b59e76f00db4b3a7f23d85ed4f99bc0f682cedf0cb6e775fe16b03da7f3b782ed599dbf0d6c0febfced60bb47e7ef00db619dbf0b6c9feafcdd60fb4ce7ef05db0f74fe3eb0fd50e7ef07db8f74fe01b0fd58e78782ed273a3f0c6c3fd5f9e160fb99ce3f08b69febfc28b0fd42e71f02db2f757e34d87ea5f363c0f66b9d1f0bb6dfe8fc04b07daef313c1f65b9d9f04b6dfe9fc64b0fd5ee71f01db173a3f056c7fd0f947c1f6479d7f0c6c7fd2f9c7c1f6679d7f026c5feafc9360fb4ae79f02dbd73aff34d8fea2f353c1f6579d7f066c7fd37969d7543bfb779d2f09e26d67bf096aa712f02dfe54997fe87c73a38c2c5b08655aeb0e85ea19877a7749da616997954ddae1f7c026edf0bb609376f81db0493bfc36d8a41d7e0b6cd20ebf09366987df009bb4c3af834ddae1d7c026edf0ab609376f815b025757e3ed8a41d9e07366987e7824ddae1396093767836d8a41d9e0536698767824ddae119609376783ad8a41d9e063669875f069bb4c32f814ddae117c126edf00b609376f879b0493bfc1cd8a41d7e166cd20e3f0c366987ef019bec2fdf804ddae6c36093b6f953b049dbfc19d8a46dfe01d8a46dfe21d8a46dfe11d8a46dfe31d8a46dfe09d8a46dfe29d8a46dfe19d8a46dfe39d8a46dfe05d8a46dfe25d8a46dfe15d8c6eafcafc1266df36fc0266df3e76093b6f9b76093b6f9776093b6f9f76093b6f90bb049dbfc07b049dbfc47b049dbfc27b049dbfc67b049dbfc25d8a46dfe0a6cd2367f0d36699bff02b667745edaea96609367c56a2afd8e138ec3d3047c094b3288b7edc7290979acbb4c95643cb3c8784692f1bc45c6730119cf20329ed3c8785a91f12c20e31947c6339f8c671919cf52329ef7c978ce25e3d944c6b3918ce744329ebd643c7bc8782e27e32924e39941c6f306198fbcf7c9c233988ce752329e33c87812643c73c9789690f12c26e379978ca70319cf06329ef5643c2793f1ec26e3d945c6d39c8ce71b329e69643c1793f1bc46c6731119cf10329eb3c8788ac978da92f15490f15c46c6339b8c671119cf42329eb7c978ce27e35947c6b3968ca7948ce754329e9d643c3bc8783a91f1b424e379898ca7868ce715329e2a329e73c878fa93f15c42c67302194f53329ede643cf790f1cc24e379938ca72319cff7c878d690f1ac26e3f92b19cfe9643cdbc978b691f1b426e33940c6339e8c671e194f3519cf7b643c87c8784ac8780690f19c44c6d38c8ce73019cf74329ed7c9785691f1ac24e339938ce703329ead643c6dc8788ac878e690f18c20e379878ce73c329e81643ca790f1b420e379998ce755329e15643ccbc978ce26e3d942c6b3998ca71d194f7b329e7d643c1f92f11410f0248023009bfcbf29d8e43b3c87c0f6b5ce1f009b7cc36701d8bed2f967c0f694c5d6c4c2270c53c126efca7e0d36b93ff334d8e49d89afc026e70de25fcd4fef70347f135846fc34b5f0a3bfaf2c5c92c7ed2dcb248378b737fa4a06f66fde15188cc79be743329e7d643cedc978da91f16c26e3d942c6733619cf72329e15643caf92f1bc4cc6d3828ce714329e81643ce791f1bc43c633828c670e194f11194f1b329ead643c1f90f19c49c6b3928c671519cfeb643cd3c9780e93f13423e339898c6700194f0919cf21329ef7c878aac978e691f18c27e33940c6d39a8c671b19cf76329ed3c978fe4ac6b39a8c670d19cff7c8783a92f1bc49c633938ce71e329ede643c4dc9784e20e3b9848ca73f19cf39643c55643caf90f1d490f1bc44c6d3928ca71319cf0e329e9d643ca792f19492f1ac25e35947c6733e19cfdb643c0bc9781691f1cc26e3b98c8ca7828ca72d194f3119cf59643c43c8782e22e3798d8ce762329e69643cdf90f13427e3d945c6b39b8ce764329ef5643c1bc8783a90f1bc4bc6b3988c670919cf5c329e0419cf19643c9792f10c26e3f93e19cf1b643c33c8780ac9782e27e3d943c6b3978ce744329e8d643c9bc878ce25e3799f8c672919cf32329ef9643ce3c8781690f1b422e3398d8c671019cf05643c6f91f18c24e39945c65349c6d3c4c273c8118f7c2b46d62df3871ab9ef3d86ef3d79e27b97e17b579ef8de61f8de9127beb719beb7e589efad86efad79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efa586efa579e27bb1e17b719ef85e68f85e9827be99afbf553f5ce9abbc4fff26e0ff15c0b8c011e3218351e61700a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba93dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba95dc0d3db114fd4bd92de04be9516f2eeb3bcf39780ffe378ebae62aab7c128f3b698da013cfd1df144dde3e94fe05b6921df0a936fd224e0ff383ea3ab98ea6f30cabc2da670fcdc018e78a2ee4d0d20f0adb4906fedca372f13f07f1cbfc9554c0d301865de1653387edc40473c51f7d40612f8565ac8b360f9467b02fe3f08185dc5d4408351e66d3185e3dd0c72c413752f7010816fa5c5609d973e5609f8ff6060741553830c4699b7c5d446e019ec8827ea1ee66002df4a8b213a2fef7024e0ff4380d1554c0d361865de1653eb816788239ea87baf43087c2b2daa745edee94fc0ffab80d1554c0d311865de16536b81a7ca114fd43de32a02df4a8b6a9d976fce25e0ff38fefb10478c5506a3cc0f0146b1ad069e6a473c51f7baab097c2b2de4dbfeabf46f02fe8fe3b1ba8aa96a8351e66d3185e3418f70c413758f7e04816fa5c5489d97316112f0ff91c0e82aa646188c326f8b291cbf72a4239ea8670b23097c2b2de4db5ccbf46f02fe5f038cae626aa4c128f3b6985a0a3c358e78161b3c8b2d5a1c2fdf4a0be9cbbd44ff26e0ffe380d1554cd5188c326f8ba9c5c033ce114fd4b39c7104be9516f26ded45fa3701ff1f0f8cae626a9cc128f3b6985a083ce31df1443d831a9f03df51cf5372e13bead9402e7c47dde7ce85efa87bb6b9f01d75ff3117bea3eea5e5c277d47da15cf88ebac7910bdf51d7ebb9f01d75ed990bdf51d751b9f01d754d900bdf51e7b7b9f01d75ae960bdf51e71dbe3df7ed79dcbe8fe7b943beb6e7c7f3187a3c8f25fedac05f1be4cab73f96f86b835cf9ced76b03df9ee7be3d97ebaf8220fa7a6cb923df4b0ddf328fcf59963af2bdd8f02df3f8cc60b123df0b0ddf328ff7bf173af25d64f896f98539f0ddd6f0dd3687bedb1bbedb5b7cbbd8de89e0c8eb6f61c02909798c81450e781cd5b354ad77895ed7b731aed776dfc6dc5f8aa1cc12d0cf75db21ebced476b48ccf7769027cc837be944d9ec5be07366943df059b3c637f076cd2cebf0d3679bef316d8e4f9cf9b601ba9f387c126cf61b1ffbb3c4bdf01b62a9dc77ed743747e1bd8a45f12f6f795be655bc126fd03b19fa9f4f1dc0c36e9a78bfd1ba5aff546b0497f79ec5727ef3cac079bbcb782fdb9e4dda3b5603ba0f3d88f48bee9b21a6c53757e15d8fea2f32bc1f6a4cedf03b62f75fe1bb0fd59e71782ed099d5f04b63fe9fc12b03daef36f80ed8f3aff3ad81ed3f9d7c0f6a8cee37b617fd0f90fc1f685cee3fb4853747e0fd87eaff3f81ecc233abf0b6cbfd3f957c13659e75f01db249d9f0fb6dfeafc3cb07daef373c13651e7e780ed373a3f1b6c13747e16d87eadf333c13656e76780ed573a3f1d6c63747e1ad846ebfccb60fba5cebf04b65fe8fc5fc1f690ce2f065b139d5f0a36197f11fb7c14eafc72b0c9b8f4d89747be953f1e6c2d747e1cd85aea7c0dd8e43b6b23c126632b8f005b42e7abc1d646e7abc026e73a43c02663890c069b9c970c025b3b9d1f08363987180036191bb23fd8e47b9ebdc17692ce57824dbe535f01b65374fe10d864fcae0560936fc01d009b8c6bfc34d8e4dbcf53c176a6ceff056c32a6c993603b5be7bf04db393aff67b0c9f7309f005b89ceff096c1d74fe71b09da7f37f049b8c37f518d82ed0f947c126e3f0fe016cf2ede42fc076a1ce4f01db453aff7bb0c9b81c8f804dc6dafc1dd83aeafc64b0c937ad2781ed329dff2dd864ecbccfc126dfeb9d08361923ed3760ebacf313c056a6f3bf065b179d1f0bb6729dff15d8baeafc18b075d3f9d160ebaef3bf045b0f9dff05d87aeabcb4336a7f56fbf9413d9f0ce23dcffe383872ca749e2d0cc813e7796b31f0a0affdb1d7bd2c758e2cfb7d13bd5e89a1fde07b5fecbed3e7e71fe97515eaf5ee337c17429996ba7150cbc931bfa95eee80b11cde139275cb329783fd4363dded747d3f7254df7d069370a30e52a68d6652c7c68d3adf12968991ad4ced03126b0168885312f2c2e046abb2523cefad0bcf47c0b33f769ef4b5af8b98c07d2bee6b5ff39ea8196bc550661fe8f7a103fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac780eea3c3e579672074918c5b61f785cdce7c7e7b0b27ef55ce7fd736bfdee8fddef91cff79ae9f5961a752e84327f86674e8b75be08fe2fdb2d6a5b3a784e98715b8abf22a80f3e0b3ae88867bfc1b3dfa285e44b62f35d36cc8dc665a5aadf8a7ac67ec0d0f5a0455357fbeb7ebdae024353dc5f3f3678f0d96811f07ea27f13b09e4fa00e0ef6f18c7121fe705fda0f36c97f0c8c2eb6331e4ba43d90e7e1f86c5acaec329e8bc7bfedcb4a5db61b7ba14ec9e0e8f82e8432fba0eddbaff3d837e420e8f633cbff65caf49c5af45375de1d7f9d53db77177026c10ffade09ac31f93ee27d94029dc48fd80b21ff53e8cf21e5440fd15ad871ec6f643797fbd858ae18caecb1d43f19c45bffdd06cf6e83596d938f21ce7e06c77f576dd29e088d2e078da4cc7ed0e880239efd068f70883f5546b67f73a38c2c5b08657e0b6d94aa8bb4f3524fecdb82c70057c731f125eb9679dbb9f147c068d651c547e7536a79f7c7cedbb0fa7ffd03da8bb8fb7ffd0362a800380263fda5b07ee16a1e441f5ba4ccff308ea32eae31705b9a7aa2ce52e67f413bf4fd92743e9b73fde375dd1675aebfc7014f2238f2da5b4d998eef788cd9eb80c7513d4b6dc7ae0f8d3a1543990ba19e0ece6332be57bb1b7cbbd8e6a8859c43ed33b42884320525e95f693ba274c46bd58f72529732ebf960a9a52e52a645496d5d5a823d4e2697db6d27d449ad77bfa5ae52a64d49ad2ec53a9f80ed84f74dceb6fc5fa64ced018e6bb33dfe3aa7b6ef36e04c821ff4fd01b0c6e4fb88ef6ac8f9bef8117b21e4cf2aa92d2be5440fd15ad8d53e22effc21bbb9dc3e63b96228b3c352ff64106ffdb71b3cdb0d66b54dda97d4e6258e5cb69b3b22342a058da40cde3f96633bbe77673beeef77c41d75dcdf0f8c66bb89e72e2ed90e186ce63d54dbf9a094c1733229d3b124fdabdad984a56cb3e0c87bc32eee63e23ba801d42330ea2a13c680836bc372bc7692764afc7402fb7e9d179d3b19da154299ae25e95f87e7ddd67b97e6f51d5e5308b7b96fe1bb1fbd4a6ab9711cc2fdfab7086c9fea5f47d769e5b67b86c261bb67982ca965c76585ebb0a52ee6357293e0e87beadf1a65f1be5ba6e5ccbc39a6a3d2f753a39ccd0f5ef3c4f6ae46e7d252646a12d8ef177c6cb01704478f5f29fb01c69c791fa593b11ebc8f726b49fa57da24b3acdaf69f9f54ab8f6c47d10edb138cc98f8131a9f3a5df6dea6cabbfcc8b3fc5f8895107376d57fa7da56cee031f001e176dbba336ba148fb1f17d9fa26795edf8ffb1a1550e9fd75a8ff9e633f796463e1edf65d5b6fb4f362df659785c3d4789d2629fc5777c5a741b663b7ed8b4c865df87282d3eb4f88e518b1178df3393167b2d3c2eee4565d262afc5777c5a742fcdf45c03b5d863e17175ef214a0bf1972df38704cc2d8d7c3cbecbab6cf7c96c5aecb6f0b8ba6e8ed262b7c5777c5a74ee86f7e83269b1cbc213fffdb9cc5aecb2f88e4f8b1e3df11e5e262d765a785c3dd38dd262a7c5778c7131dc762fc7a6c50e0bcf8e1c6bb1c3e23bc6f3c36eb67b6d362db65b781cdc77cda8c5768bef18b5188af75d3369b1cdc2b32dc75a6cb3f88e4f8baaaeb67bc2362d3eb0f0b8ba271ca5c50716dff16931b487f2bdb50e5a6cb5f06ccdb1165b2dbe63bc864ac5c5963a68b1c5c2b325c75a6cb1f88e4f8bead4b9d6e63a68b1d9c2b339c75a6cb6f88e4f8bd2d43175531db4d864e1d994632d36597cc71817a9ebc98d75d062a38567638eb5d868f11de3712415171beaa0c5060bcf861c6bb1c1e23b3e2d46a4ee3fadaf8316eb2d3ceb73acc57a8bef18efb9a4e2625d1db45867e15997632dd6597cc7a74597d431756d1db4586be1599b632dd65a7cc7a7c5f0d433b13575d0628d85674d8eb55863f11de37967aabd585d072d565b7856e7588bd516df319e77a6ee5facaa8316ab2c3cab72acc52a8bef18dbced479e7ca3a68b1d2c2b332c75aacb4f88ef1bc33a5c58a3a68b1c2c2b322c75aacb0f88ef1bc33751c595e072d965b7896e7588be516df31c645aaed5c56072d96597896e5588b6516df31ded74ab59d4beba0c5520b8fabf11aa2b4586af11de3f548ea1edf923a68b1c4c2b324c75a2cb1f88ef15951ea1c7c711db4586ce1599c632d1683ef03b1fb4ef7e7161fd217eb32438b4228f36d49fa57fa6245e928ebc07e65589745b1d725ddaf6c61445d16415da44c6187dabab40c9c8cf753eea8aea99859007552ebfdc4525729d3aa43ad2e099d4fc036390cba9d61f9bf4c05c67c12f2a29faaf37bf1d73915abef026712fca0ef77803526df9dd177814ee247ec85903fbd436d5929277a88d6c2aef691f7751ed9cde5161bcb154399f72df54f06f1d6ff3d83e73d83596d936288338923376d579ae9fd088d2e038da40cf6d9fbc4118fd9875038c49f2a23dbbfb95106fb504a99f3a08dc27ea552cf447074bf49476d5967649775cbbcf82b06db016034eba8e2631ff4fd94b122641c0965937121bac07aba1b3655d71e8eea2abe64dd32df0318659c8aeeb9672cab2b63378351f1f472a0198ebd2153a6e3452fe0e9e980c7513d53c7a10aa34e3d8c3a1543197cb7b1c2413d0bc0afac5be62bc0b78b6d8e5ac831f962438b42ac37b46799749475a8f8ed6ea94b1fc77591754bbbd42707be2b0ddf5d0ddf89e0c8ed1c0499f7af4a60eeed8059adb76ffceb2dc5f3368929f1d315ead40f3488ab4eb82e39cfeb67685b08f9fe709e27e5a4ac1cbf845dc5b26c4b643797eb652c570c65fa58ea9f0ce2ad7f5f83a7afc1acb6c90d706ee7607f48c5401f8343e6bb82767d23b4eb03da49193cfe7573a45d6f8347e6bb018f9ce354804dce15843f01ffef92036eb3ddabb0708b0dc789eb6661ec1a3f63ea5ca79bc128f35d81516cbd81a7d29166e6b6bed8d0078fcbcd8d32b26c219479088e8d094b59b5df5d58505bafa6da1edbbb63ba4d6fee402f1ca731007d0243c300f4927a3673c0d33aa81dab71e2a49a09431f1c7ec7f0f4a347412b3430f1b7c0528d2660c37c538b2d088e1c92b2106c32246533b0353164c1a130a5bc0c69e7422ed443d65d6870b60496387de3709e32650a9d16c0e3229455e8c8909e3a74ee99306ad2708c8f6606677d6247fdaf69867251eb72b51dcc7d2209f3660c163af2df14ea9b8479f1a7b68d0cad3a6ee8b087fb4d7870f298e163274d44a1cc1d1bf305c1911bc0fc8d12dcd54e87018015c6c6a199512f6c30e47fb2615ac7cf598e63e69ada04e04fa6d6a05b2b07baa9f5cbd8b7c3868e1e7ddbe4aad1a3865d3379ecb049a36ac6e2d66c692817b5a5e5ffcdc1666be2b1ac9ab0d9c2655b586cb60947196e09363972b5029bf0b4065b53c84b7973cb3809d70b60fdb24ba9ff29719ae98ab7086a43400ec7aa5d55fbaf3a95539f9055a7426a6863b539d5d0c5ea8ea11a9a587dc54e0d3dac861a56430b9f11a4870e5643059f1da48702565fbb2809d243fb9e17d40eddaba6c3c0f9bd203d34afba4d7351903eed5243eb760cd243e7aa5b979d82f467ded4bbf5eaf45ddd1650a7bcea124f9d7eaad34e7579a16e5fa85b59ea944e9d2eab534175faa62e47fa6aadfb85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bb82f4f0ce7707e9e1d7d5f0cff706e9a1a1ef0bd2c346df1fa487947e20480f373d34480f453d2c480f533d3c480f61fd60901ede7a54901e26f7e1203dd4ae1a82776c901e0e5b0d93ad86cf56c3fcaa2181d590c26aa861352cb11ac2580d81ac86467e3c480fb9ac866c7e2a480ffb3c354ccf84e9d9303d17a6e7c3f442985e0cd2c383ab61c3a705e961c6d5f0e33383f470e5b383f4f0e66ad873351cba1a265d0d9fae865557c3bcabe1dfd5b0f06f86e9ad30bd1da41f49a84731ea1185bafdaf1e83a95bd48b82f4adf32541fa11b77ae4afba40a82e21aa8bccaa20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a7f90be2d7e30483f2a55b7c3d5a301158feaf6fd6761fa41987e18a61f85e9c761fa49987e1aa69f85e9e7417a586335dcb11a2e590dadac8661564336aba19cd550d06ad8e82f82f4d0d36ae8ea3f05e921b1bf0cd35761fa3a480faffdd730fd2d4cdf84e9ef61fa4798fe19a67f05b54369636371866e61f4554a3074d2a4e163c64d2a9954533266f2e849a3c68d7eac64caa849234b6a1e193e61c4e89a29b8f00ff5c2320e78bf0913863e56326a6cf5f0474b6a264f2aa91951525533796cf51107ea7fea85ce3adae3d0eaea6867fffe5d48ff6f3d9db6d26d9f8cb07e7de6bab5695a0f414ea8cf42dd9ad6af4213f4514a2e67ef4c9feb964c1c5d33a9a4b4646cf8373cb8d64c195edda904ff37311479e2a4928993864e9854326242cd9892ce9d70bd4fb7ae4725fea3b51b985667d44f9c16fa5b4af50ab19de7d64381cfcfad1fe9dfbf0be9bfd5d369eac09b6d0d9bd767a14b4aea47585e1229cbc4c95593260c1d36297ae19edf65e1bef5a9e62df5ace67fd5c759d30ef558a84387fa11f6ad8fb35159380bfe3f244cae11d44d06009b2d6c6f00000027cc1f8b08000000000000ffed9d77701cc795c667911856581024981324db1423b8586430813953a6242b072650a44512140925cbb2244b72ce395b4e6739e77c9673ce39e7ecba2adf3f57bef255b9ae7bb69ff1a139b3c6aee6816fb06faa1eb6e76defbc5f7ff3a667b67b7690098acb9f8d655cb9d6d8638273177a7fc0bde61fddd29ee0b6f29c9c999470d6a484b336259c7529e1ac4f0967434a3827a58473724a38a724c899013e2edea929e3cda68cf782201d79db9812ce5c4a389b52c2392d259ccd29e19c9e12ce1929e16c4909e7cc9470ce4a09e7ec9470ce4909e7dc9470ce4b09e7fc94702e4809e7c294702e4a09e7e29470b6a684f3c294705e9420e70ae0a431f2c7bad7c7b9d725eef562f7bad4bd2e73afcb5d1bebdcbadde64a63ab8cb579efadb6ccc6ec6079c17bafc358a7b12e63ddeebd56f75e8fb15e637dc6fa8dad31b6d6d83a63eb8d6d709a6c34b6c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd825c61e6f6cbfb14b8d5d66ec72634f307685c772a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b8d9d3076d2d8296343c64e1bbbc5d81963678d0d1bbbd5d86d9e66b71bbbc3d89dc69ee471de65ecc9c6ee36f61463f718bbd7d87dc69e6aec7e630f187bd0d8d38c3dddd8338c3dd3d8b38c3ddbd8738c3dd7d8f38c3ddfd80b8cbdd0d88b8cbdd8d84b8cbdd4d8cb8cbddcd82b8cbdd2d8ab1c0b1d08af36f61a63af35f63a63af37f690b137187ba3b137197bb3b1b718fb0f636f35f6b0b1b7197bbbb177187ba7b177197bb7b1f7187bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fb4f639f34f688b14f19fbb4b1cf18fbacb1cf19fbbcb12f18fba2b12f19fbb2b1af18fbaaa7f9d78c7dddd8378c7dd3f9bee55ebfedead231ff1df7fa5df7fa3df7fa7df7fa03affe0fbdf51f79eb3f76af3f71af3f75af3f73af3f77afbf70afbf74afbf72afbf76afbf71afbf75afbf73afbf77af7f70af7f74af7f72af765e6dc5cc62797230b20c0409f5499d837d765c9dc4f6e7edec9c50ad7b8f5e5b9dbfceadd36bc6f9ebdd7abde76f70eb0dde7626bbf5c99e3fe7d6739e7f9a5b9fe6f9a7bbf5e99ebfc5adb778fe0bddfa85e0cfbaf78a0d2bbe585fad7365c047f95903be7ae7ab055f036d0e7c939caf1e7cb47f1bc037c5f926816faaf34d065fd6f9a69096c62e70be8120a95cc91fb4db6d4c7abb6e2e22973cef21bbdd2626de69c9f31eb6db6d66e0b5f931dd6dab11f26686f3e5c0d7e27c4de0735dd0bf8e39eb9be57ccde09bed7cd3c137c7f966806faef3b5806f9ef3cd04df7ce79b05be05ce371b7c0b9d6f0ef81639df5cf02d76be79e06b75bef9e0bbd0f91680ef22e75b083eea2f1781efb1ceb7187c746dd70a3ebacebb107c74cd7791f3d97e627206e2393ff551613cea9fc1f738ea9bc1b784fa65f05d4c7d32f896426cf22d837e857ccb9d8ffa28fb5ebf2b0f04491d1385f0185e93f476cd96ed76d725bfdd700e6c7d30a2f500c459035a6d70e504ef0f69c7d8741d4371c85f07e59d5097ea911e749e2176dbefaf75e50d253ed7ef7d2e0775d646b47f2048b6fdeb3c9e751e733db49f29678f6ace8e79293b67af84ba7eeed135cf44ccd93dc0917cce767468ce8e79293b6707a1ae9f7b74dd3b1173f61ae060c8d91e9e9c2de435678be36041109d7bf4dd6722e6ec31e0483e67bb3467c7be949db3f7415d3ff7e8fbef44ccd9db8023f99cede9d16b83312f65e7ecf3a1ae9f7b3416331173f601e060c8d943dacf8e79293b675f0b75fddca371c18998b32f028ee473b68f29673b346783e29c661044e71e8d514fc49c7d083892cfd9c33a3e3bf6a5ec9cfd18d4f5738fe64b2662cebedb95ed3cc3b7dc3cc302f07ddbf916026ff2b97da49d29b7db35b78bf77a0441748ed2dcdd44cced475cd9e6f177e1de03f27d8fee4b00dff79def22f0fdc0bb6783e918e8d66360ec6d2af718f819d4f57399e69127e231f06de060c8d91ecdd9b1b7a9dc9cfd0bd4f5738fee69988839fb4be060c8d95ecdd9b1b7a9dc9cfd3bd4f5736fa92b4fc49cfd2f57b6d70b3f71d70bcbc1f753e75b01be9f39df4af0fddcf95681ef17ced706be5f3adf6af0fdcaf9f2e0fbb5f3b583ef37ce5700df6f9daf037cbf73be4ef0fddef9bac0f707e7eb06df1f9daf077c7f72be5ef0fdd9f9fa9ccfde9347f75e7dd1f9ecbe258d068264f72ddd6349dba6f595e310bbc98bdd348eb19bbdd8cd11b15731c4ce420c5a32defa009457f1f2e473c083b156271fabc3b6bd2d187bdb57034f9ea1ed598831169e3cf0b427cf139e3f0bc96f37dcc76d9ea65988d506edea6068570662d1b6699de2e5c087fd7747046367f28c850cc4a26dd37a2730920fcf27745ea7e3c79e0f97644678198ea5f09a88e2d1f39f886335f8a9ce375b46d8963bb646781fcfaded9e8f292fc3bca058b46d5aa7788dd09ef6f1672c8c9531ef3172f511198845dbf663e3f1be6afc351bd37ecd81ef3cf449854afba446601b8feb94b87d2d2536c7f92a0331a86f23cd0be0a73ab3dc0f126cdfb61dfa5d86e3af50eef51bf607c9e771218fc7f558783a8087e3d8673a5ef378deff67906cae75795ab57b5ae5a04e27e8d7c5a05fa9eb108aa7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1fe0b9cdfa47a2b853092af003c1ce3fce133a0dcb668fb765ee7c730af93fcbc45218f7396748fe132afcd7550e7af9991ba3f87f9747f6e10e73457f26a37a6fb2c1a8373e76239e710e3e681a3e62f5b138b5d38cc35df66ef51b3cf216bf3745d19a129c37d2aa334cd789ae27d8a2b3c1e9ba7736b47d838e6feca9d8b44ada89ce4dc1ede63c0bb5f8afd07e5424d30baffc0f34c77e2b147cf61d27c79b717bb0eeafc6f6664dfd0bda8f4bfeefc7b9e6c9d1e6fdbf49965e0eff1b63dcd7d9638eabdedb7c167a9ceff419ffaba9ae05f9a71dcff81fd72006dc56500ca386f9efc79b8388fdf51064f17f070f4334cd71b793c06929ec7eff1b48aba8ea13adda05f0f837e51d7a2b44ef194599995599995599995599995599995599995599995599995599995599995593e33fe569458b350af2084719cee7d08e733e8f92fb47d3baff39c9a91b8dcf37034e7b4dc6b731dd4f946cd48dd17b8726370eefd0e71fb92613eafe4bea4788dd01e9c0be2fa3d77a7c7d319a105955b138b5d9cc74f5ee39179fc0e4fd74284a65cc72bceb1a2a678bcb67b3c3837da189c7b6f4916b6331ef70ec5e505c5c363a9137c54c6df4773ec673c97f8f7f5503c9cbf7ed8693b2de0daf7853c67bfd10b6d1a08cecdef3aa8f32ee8fbdee3ca780f07de3bf248c4fbb4949aa726fd589e65972fcefbae01ce018883b1d7026b42b1db3176c619c5217f1d943f59335297ea911ea435b1db63849e0986ecfee7dabdcfe5a04e5f44fb078264dbdfeff1f47bcc769fbc1ff2ec1138ff73f5497d311a2d038da80e5e0771dd93e7f791fefd8d78df5e835707af59a8ce17a18f8abb7f34ea9e43aef358dc3d8751d7c65dc0e8b7d1bfcfb3daefd3fa21f41749dfa7f543c821bc4f2bf0b6bf1cb64f5c0d41fcb985eafcd4dbbe7f4d4e9fc1fbc0a8ce2fa0bf6872f72c3606e75e7fe33d53e3f1fd2aee3e698a87d735786cffbbb65be65ea83f902033e604b2e07502d5f993b7cf7a62b857477cf6af319f25ade83954f8fdc5d7cfead0079f19484487e231dfefb585f2ba0fda4275fedbbb064cfebaa5780d987c5b475f93503fd019d156aaf33f70acfd1daef1683fe1f78e86da73dfa7a5d43520e967db3cdecf07c6d8129e0f5c5f3b52d77fce2f695deef381bbbdcf497c3ef03f20cf1ae03e74aebe7a6d8c46cb4123aa83bf0da2f3083ecb37ea1cc3756f7fdc3926ea1994d83f37d58e3f9b3fae16758d4075e8b3788dd0e298a7399dfdbafe78219d2f93bc6f187f2bd10671f1b7126d4c7ae641b70158c7eb82f3193bcf143bee99d3f971881df7cce9f188ddecc56e1ec7d8aab96a2e497386672287bf3fc36796daa5d4752931e4e073352960ac4d01635d0a18eb53c0d89002c64929609c9c02c62929609c9a02c62c309ecf733b833e854af5e1da5fa5ae353036c3ff2e2994fbff3b98ff974ac96b1f8ccdf09d2ed4625530762df07b1ec7b31fcafd5f2fc480ffbb607a0a1867a480b125058c3353c0382b058cb353c03827058c7353c0382f058cf353c0b820058c0b53c0b828058c8b53c0d89a02c60b53c078510a181f9302c6c7a680f17129605ca28c8930aee0652c54ca687938fee7dfa3f99f630c3cf9a87b4e997e7b52f6ff5b637e3e697ba5cf8dc37b4b78ff27dca37bb61dc7bd23e53edbaed4ff5b65622c54cac8751f3bfe8e672c3cf8bbc8a8dfd63030162a65e4fafd0bfe466f2c3cdda0595784660c8c854a19b9ee952bf75e4ebca7bf3b423306c642a58c785f75823ca1663d65f0f482663d119a3130162a65e4ba2f390b31c6c2d3079af54668c6c058a89491e9b76da1667d65f0e06fc0fa223463602c54ca6879d63069d65f06cf1ad0ac3f4233498cc893f473b2fb236271fc66b0dcb61303324e4901e3d41430e27d121cfd57a9fb24fa79f52954aa0fd7fe2a759f04c666f87d4ca805fe1ee2df69b18e97a7e47d12187b3d9316f87b957fa7c57ae0e1f8fd4c16628c85871872f0b9e929609c9102c6961430ce4c01e3ac1430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01237e5765b8562cf9fd65fd048f1df75d65a2c78efb5e32d1636b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae79262a7618c5f19271e23f2b426c793c7b663ac01016d1f88e0c930b51d636d14d07662481be3861430ae4901a3ea58bc07b11246cbb389896763193c9b80673313cfa632783603cf96e479c29cda5c060f31e4e0736b52c0b821058caaa3ea28895175ac1e1d955119955119cf07631afa70654c453e162a65b43c5b93e70935db5206cf56d08c3ed7cecb58a894d1f26c4b9e27d46c6b193cdb40b3ad119a3130162a65b43cdb93e70935db5606cf76d06c5b84660c8c854a192dcf8ee47942cdb697c1b30334db1ea1190363a15246cbb333799e50b31d65f0ec04cd764468c6c058a894d1f2ec4a9e27d46c67193cbb40b39d119a3130162a65b43cbb93e70935db5506cf6ed06c5784660c8c854a192dcf9ee47942cd7697c1b30734db1da1190363a15246cbb337799e50b33d65f0ec05cdf644682695714d0a1837a4809159c742a58c96671f13cfde3278f601cf254c3cfbcae0b904781e9f3c4f98539794c1430c39f8dc9a14306e4801a3eaa83a4a62541dab4747655446652c8f7120058cbaaf95512a23c3f7ab92bfa1b96482c76ef262375549ecb8dfd04cf4d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e6b9a4d8fb938f5d28f71933fb8187e399374cedccdbed5eeab6f5cf04f5b35a5de6697589a7550eea5c0afa5dc6a05f06e2d2b6699de295cb7cb10066a6d805dbbf4c81f6538c0d9e1e36fee54c6d8febeb2f9fe0b1e3fafa891e3baeaf9fe8b135cf35cfab21b6e6b9e67935c4d63cd73c97121bcbf5c1c8753b3dffd46ee309ae5ce7d69195fc54e7f1938aafd3023d863862eb31a4e78a6a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9ecbcbf31cbc5f330e3c81c71394e059248c678e309ee9c278a608e359268ca75618cf7a613ce3713f5f393cbb84f16c17c6d32b8c67b1309ee5c278e60ae32908e399218ca74b18cf54613c5b84f1d409e3d9288c272f8c678f309e25c278e609e36911c6b342184f56184fbd309e4dc278560be3592a8c67af309eddc278fa85f1ec10c6d3278ca75b18cf7c613c1dc278660ae36913c67381309e46613c5b85f13408e359258c679f309eb5c2781608e399258c27278ca74918cf24613ceb84f1ec14c6b34d184f8f309e85c2783a85f1cc16c6b35218cf34613ccdc278360be3992c8c272380271b9cfb4cb22cbcbf1f7c35de67edf540f3cc91f7af70fe1af8cc95ae5c1bb1ed2bc047bf0dbf32e2b3a8d315d0960157ce3fba25d409630dc03ac56b048e2b85f04c16c6b359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278b609e3d9298c679d309e49c2789a84f1e484f1cc12c6b34018cf5a613cfb84f1ac12c6d3208c67ab309e46613c1708e36913c63353184f87309ef9c278ba85f1f409e3d9218ca75f18cf6e613c7b85f12c15c6b35a18cf26613cf5c278b2c2785608e36911c6334f18cf12613c7b84f1e485f16c14c653278c678b309ea9c278ba84f1cc10c65310c6335718cf72613c8b85f1f40ae3d92e8c6797309efdc278d60be3a915c6b34c18cf14613cd385f1cc11c6b348184f4d040fc3ffbf0c79e8fe35da36adef17129b613f84fff7f32aa6365dedb655efb64bfc14af0eea5ce33a0a7b7f157e96b8fcfb0df1dc7435687435535b687f64bcfdc31d1befab0c8021f0f409227838ee47656ae7a83c4cf0ffcfe6ad56d7785af9fb2e0775ae02fdae61d02f2ab7ff750c000f5de7106b16eaad17c248becb9979b2d0665a4a1d03d7000fc731c9d4ce3057aff5dab43e4277aa83b97a2d433ba38e1d5abf167836ba32b166a1de46218ce4bb9a99270b6da6a554ae5e0b3c1cc70e533bc35cbdce6bd3c608dda90ee6ea750ced8c3a7668fd3ae0d9e4cac49a857a9b843092ef1a5e9ece2cb4999652b97a1df0701c3b4ced0c73f57aaf4d9b2274a73a98abd733b433ead8a1f5eb613f28b33247315b1efa9d0eb166a1de66218ce4bb9695a7339f8536d352aa1fbb1e7838fa7926ddc37eec06af4d9b2374a73a98ab3730b433ead8a1f51b2262b706c96a71e318b4b83182e7c671d682e295cb7c550a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7f161569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d5b93266cb43cf4522d62cd4db2284917cd7f1f284bf0bda128c5e32defa00946f049eeb19f4616a67780ff901af4d5b2274a73a787c1d606867d4b143eb07603f1c2883f9861432abce95315b1e7afe38b166a1de56218ce4bb9e9727ecc7b606a39752fdd801e0e1e8e799da19f66307bd366d8dd09deae0f17590a19d51c70ead533c6556e63866cb43ff078858b3506f9b1046f2ddc8ca53087fdfb82d18bd94eac70e02cf81c4798afd1883ee613f76c86bd3b608dda90ee6ea218676461d3bb47e08f64339cc37a4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7ead1d9f2d0ff8321d62cd4db2e84917c0758793ac27987edc1e825e3ad0f40f910f01c4c9ca738efc0a07b38ef70d86bd3f608dda90e1e5f8719da1975ecd0fa61d80f139df98614326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03c3b5c9958b3506f871046f21de4e5099f7bb02318bd94ba6fe730f01c62d087a99de17d3b47bc36ed88d09deae0f17584a19d51c70ead1f81fda0ccca1cc56c7976ba32b166a1de4e218ce43bc4cb13f6633b83d14ba97eec08f070f4f34ced0cfbb141af4d3b2374a73a98ab830ced8c3a76687d10f683322b7314b3e5d9e5cac49a857abb843092ef302f4fd88fed0a462fa5fab141e0e1e8e799da19f66347bd36ed8ad09dea60ae1e656867d4b143eb47613f28b33247315b9eddae4cac59a8b75b0823f98e30f364a1cdb494eac78e020f473fcfd4ceb01fbbc96bd3ee08dda90ee6ea4d0ced8c3a7668fd26e0d9e3cac49a857a7b8430926f9099270b6da6a554aede043c1cc70e533bc35c3de6b5694f84ee540773f518433ba38e1d5a3f063c7b5d9958b3506faf1046f21d65e6c9429b692995abc78087e3d8616a6798abc7bd36ed8dd09dea60ae1e676867d4b143ebc781679f2b136b16eaed13c2483eecc7f631f1347a3c8d115a4cc4d84d5eeca62a89ddecc56eae92d89ae79ae7d5105bf35cf3bc1a626b9e6b9e5743ec6acd35d5bc3a35cf9c47cd33e751f38c6a2e52f37f2617bb2b178c2c35108b617cae7d2c638ec8b34818cf1c613cd385f14c11c6b34c184fad309e5e613c8b85f12c17c63357184f4118cf0c613c5dc278a60ae3a913c69317c6b34418cf3c613c2dc2785608e3c90ae3a917c6b35a18cf52613cfdc278fa84f1740be3992f8ca74318cf4c613c6dc2782e10c6d3288ca74118cf2a613c6b85f12c10c6334b184f4e184f93309efdc2782609e359278ca74718cf42613c9dc278660be359298c679a309e66613c9385f16404f06483737fdb81bf27a8051fdddfbf0f7c4f74e5fde0ab898841db390e3e1acfa56dd8f3d58299e732d4c0676e8ee07a62443c8a7373c467c743778c3500eb14af11386e16c23359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278d609e399248c67bf309e26613c39613cb384f12c10c6b35618cf2a613c0dc2781a85f15c208ca74d18cf4c613c1dc278e60be3e916c6d3278ca75f18cf52613cab85f1d40be3c90ae359218ca74518cf3c613c4b84f1e485f1d409e3992a8ca74b18cf0c613c05613c7385f12c17c6b358184faf309e5a613ccb84f14c11c6335d18cf1c613c8b84f1d444f0ec67e2897b9ec27e01b1edb8375d0bd2985816de1f8fdf29edf71869fd1830920fefd3cd33f1c43d83222f20b6d5623594ed9285f7f177265c3995f718693d2aa7f03ecbd54c3c71cfed582d20b6d582e606e81e802cbc8ff75573e5d46a8f91d6a372aa999727fcff01ab82d14ba97b8df098e3d8874cedcce3f197e03334229f91bccad32a0775c6e3bee2b8fe80e229b332c7315b1e9afb22563c9f8dc7ef96c6c218757e65e009fbc7b660f452aa7f3c063c1ce70fa67686fdd809af4d6d11ba531dccd5130ced8c3a7668fd4444ecd620592d4e8e418b93113c27c7590b8a572ef3fe14324bd0d9f2d0bd9ac49a857a2b8530922fcfcb13f68f2b83d14ba9fef124f0709c3f98da19f609a7bc36ad8cd09deae0f1758aa19d51c70ead9f82fd500ef3891432abce95315b1e9aa321d62cd42b086124df31569e423e0b6da6a5543f760a7838fa7926ddc37e6cc86b53214277aa83c7d710433ba38e1d5a1f82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2992d0ffd769858b350af430823f94eb2f214e71d3a82d14ba9798721e03995384f71de8141f770dee1b4d7a68e08dda90ee6ea698676461d3bb47e1af683322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf40c7962cd42bd4e218ce43bc5cb13fe6eab3318bd949a77380d3c1cf3324ced0ce71d6ef1dad419a13bd5c15cbd85a19d51c70eaddf02fb419995398ad9f2d0b30789350bf5ba8430926f8895a7387fda158c5e4af563b7000f473fcfa47bd88f9df1dad415a13bd5c15c3dc3d0cea86387d6cfc07e2887f9440a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975ae1e9d2d0ffd4f4362cd42bd6e218ce43bcdcad311ce3b7407a39752f30e678087635e8649f770dee1acd7a6ee08dda90e1e5f6719da1975ecd0fa59d80f139df9440a993537c68759734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426e589e1e5726d62cd4eb11c248be5b7879c2e71ef404a39752f7ed9c059e330cfa30b533bc6f67d86b534f84ee54078faf618676461d3bb43e0cfb419995398ad9f2f4ba32b166a15eaf1046f29d61e6c9429b6929d58f0d030f473fcfd4ceb01fbbd56b536f84ee540773f5568676461d3bb47e2bf0f4b932b166a15e9f1046f2e139ae8f89a7d1e3698cd0e27cc5b65af4bbf205ee350beff7032357dfd2e731d23ae638f91a81a79f89a7c9e3698ad0e27cc5b65aac85b25db2f0fe5a60e4caa97e8f91d6a372aa0978d632f1347b3ccd115a9cafd8568b75ae3ccdbd66e1fd75c0c895536b3d465a8fcaa966e059c7c413d727ad1b87d871c7d778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c478563a7142300065c06a08cdf1538ae3d99da998ffa3eb6ce6b137e1fc33187f3f57d439995398e9969dca233ebc5267d028f879661662dc6730cb2df6b93b431c872994fa4905975ae8cd9c6be2df9d89d592f36e913783cb4dcc6ac05533bc3fee0f6205a638a97833a98a7b733b433037169dbb47e3bec8772984fa4905975ae8cd9c6be23f1d8c567b3636cd227f07868b983590b9e7616fb833b83688d295e0eea609edec9d0ce0cc4a56dd3fa9db01f945999955999955999955999955999955999955999955999955999955999955936b38dfda4c46317c7ef3136e913783cb43c89590b9e7616c7efef0aa235a67839a883fbfc2e867666202e6d9bd6ef82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec27271f3bfc3d0ec6267d028f879627336bc1d4ce70fcfeee205a638a97833ab8cfef66686706e2d2b669fd6ed80fcaaccc51cc36f653128f5d9ccfc3d8a44fe0f1d0f214662d78da59ec0fee09a235a67839a883fbfc1e867666202e6d9bd6ef81fd500ef3891432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c3d3adbd8f7261ebb231cbfc7d8a44fe0f1d0722fb3163ced2c8edfdf17446b4cf1725007f3f43e867666202e6d9bd6295e35309f4821b3e6c6f8306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80d1bfba9c9c70e7fcf8eb1499fc0e3a1e5a9cc5a30b533bcffe5fe205a638a97833a98a7f733b433037169dbb47e3fec076556e628661bfb0186d8592f36e913783cb43cc0ac05533bc3fee0c1205a638a97833ab8cf1f64686706e2d2b669fd41888d7a27143bbc079262d4b857eb7b9a2bd782efe9ae5c07be67b8723df89ee9ca0de07b962b4f02dfb3a13de47b8e2baf00df735d791df89ee7ca6bc1f77c57ee07df0b5cb90f7c2f74e561f0bdc8956f05df8b5df936f0bdc4956f07df4b5df90ef0bdcc95ef04dfcb5df949e07b852bdf05be57baf293c1f72a57be1b7caf76e5a780ef35ae7c0ff85eebcaf782ef75ae7c1ff85eefca4bc0f75084ef0daefc54f0bdd195ef07df9b5c793ff8deecca53c0f716579e0abeff8032bdbed5952f00dfc3aedc08beb7b9720e7c6f77e526f0bdc395a781ef9daedc0cbe77b9f274f0bddb956780ef3daedc02bef7baf24cf0bdcf956781effdae3c1b7c1f70e539e0fba02bcf05df875c791ef83eeccaf3c1f711575e00be8fbaf242f07dcc951781efe3aebc187c9f7065dcbfffe9ca0f808ffa9507c147fdcad3c047fdcad3c147fdca33c047fdca33c147fdcab3c047fdcab3c14779f71cf051de3d177c9477cf031fe5ddf3c14779f702f051debd107c94772f021fe5dd8bc14779f712f051debd147c94772f031fe5ddcbc14779f70af051debd127c9477af021fe5ddabc14779f71af051debd167c9477af031fe5ddebc14779f710f828efde003ecabb3782afd595df04be0b5df9cde0bbc895df02bec7b832f6338f75e5b782ef71aefc30f8a82f7c1bf82e76e5b7836fa92bbf037ccb5cf99de05beecaef02df0a577e37f856baf27bc0b7ca95df0bbe36577e1ff856bbf2fbc19777e50f80afdd953f08be822b7f087c1daefc61f075baf247c0d7e5ca1f055fb72b7f0c7c3daefc71f0f5baf227c047e771ea67ecf16c8f41d28134b23e6a735b445bc83719da3210247b4d47b168dbb4de018cb40f0ae3cf58182b63bbc76879ba1834c3bca2a5d4f78f2ee0e964e0616a67f8fda3db6b5387d7a61cd4b918dad9cdd0ce0cc4a56dd37a37c4e6d8e7a845bddbee524f8b3aa8f3077792b3e7ce523ad2366cfe1622dad2c7dc16da36f54b7de310bbc78b9df762637f4c4ba9e3ab07987b1998ed76fb93df6e787cad71dba29ca2387968d35ad020a93661ec8c338a43fe3a28ffa365a42ed5233de8fc45ec3697695f22bbffb92eef7339a8d317d1fe8120d9f6f77b3cfd1eb3dd277f6b19e160381ec21ce8f338683d0fdaf5c768d707da511d3cff1598b4ebf5787abdd89687ae71bac147d70ac48fd7596de3c0edf77bdd11dce4eb01c6a86b9df6e4194b5eebb40323f97a81a78749337f5f2ff5f4c1f3728357873e5b07759adc97bd69c1e8ef1f54d71e774b3223eda2efe0ff0c92edd31b18f4c2f18100f4093c0d03d08bda59cfc03335181923383b3c74e6e04d83970e1e3c9201b43a0f135f3311cda8011f966b237c41307a2804876469280487646b3c59700886eadbaf52b65934dc3078f2f8f0134e0d9e3a7ce6ced3c38347f60cdd84d4f51e3d92c6b50049d147cbe46064d066204836791abc58a5926732bc4e62e0616a6778d29be2b5a9c16b530eead4c37b5318da9981b8b46d5ac70160f26176d2fb386150e3b505b3780abcfafb36d10651c0c7c0f6330ecebe57e7846d70f0242ef5187614d15ec9d91d6147056d6f6d47fdec616747f5ec8591edc8ed289d1d95b3a37076d4cd8eb2d951353b8a6647cdec28991d156b0d8aa35e1701cf1781d18e6ad9512c3b6a65bf49dab3821d85b2a34e7694c95e4dd86f29f60c6caf38edd5913d23da33a1fd3665bf59db338c3d7bdb33933d9bd8ab237b5564af62ed559d9d99596f6c83d37aa3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e31f6f8a038a27ca9b1cb8c5d6eec09c6ae3076a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b83e21d1e278d9d323664ecb4b15b8c9d31763628ce12d959213b0b64677dec2c8f9dd5b1b33876d6c6ced2d859193b0b63675dee0d8ab32a7676c4ce86d891703bf26d47baedc8f63382e2c8b51da97e76501c89b623cf76a4d98e2cdb91643b726c478aedc8b01d09b623bf76a4d78eecda915c3b726b476aedc8ac1d89b523af76a4d58eac3e1414474eed48a91d19b523a176e4d38e74da91cd8783e2c8a51da9b423937624d28e3cda91463bb2684712edc8a11d29b423837624d08efcd9913e3bb26747f2ecc89d1da9b323737624ee93c61e31f629639f36f619639f35f639639f37f685a098935f32f665635f31f655635f33f67563df30f64d63df32f66d63df31f65d63df33f67d633f30f643633f32f663633f31f653633f33f67363bf30f64b63bf32f66b63bf31f65b63bf33f67b637f30f647637f32f6e76064d41e3b8abfbb151a413e383c3c78f2f470ebf050ebc95b4f0c1f3f7de2ced6db8f0f1f6b1dba6df0ccd11343b7e387dfeaba261a1edf78e6ccc13b5b8f9f3a327847ebd0adc3ad43475b0f0ddd7aeac859fcd017dc87169c1bf1e09123f1c17e50f328487f5261d03fbacfd1c4c3ced26dfb4b2582fcad920fcda8adac4197b8330b7d2bbdac7815d77af6c4d0706bbef594f97bf084f9cce091b6567cefac11f9ec70ebd9e18367865b8f9e193ad9dade86dbbd7a4a058df87d4b051fcacd1c7bcb83ff079bac954d69010400", + "packedBytecode": "0x000000028df71de50000003d241f8b08000000000000ffed9d079c1545beef7b8621e87146cc028651519078e630648483398b2092c330e41c86282819441104910c43ce8860d8e866379936e8aebb77f7eedebcf7ed0b9ff73ef7bef7ee7d6fefeb3aa7fe6f7e14d5e39cb16bfc8d547f3e35a7fa37d55ddffa757575a8eeaebc203bfd290c793ade200c2d830b27f97f5aff263fdf5412e3ba922e39f3ea09677e3de16c504f380bea0967c37ac2d9a89e7036ae279c4dea09e725f584f3d27ac299a8279c97d513cec27ac259544f382faf279c4deb09e715f584f3ca7ac279553de1bcba9e705e534f38afad279cd7d513ceebeb0967b37ac2d9bc9e70b6a8279c37d413ce1beb09e74df584f3e67ac2595c4f386fa9279cb7d613cedb62e46c0b9c72cffe76fd7b87fe6da57f5bebdf3bf56f1bfddb5697b140cfb70b43fb3074084347e37fca1875e33e15864ec6ff4ac3d0390c5dc2d055ffaf58ffaf5b18ba87a147187a86a15718ee0a43ef30f4d17ef40dc3dd61b8270cf786e1be30dc1f8607c2f060181e0ac3c36178240c8f86e1b1303c1e8627c2d02f0c4f86a17f180684e1a9300c0cc3d3611864b00c0ec390300c0dc3b0300c0fc388308c0cc3a8308c0e435918c684a13c0c63c3302e0ce3c330210c13c330290c93c330250c53c3302d0cd3c330230c33c3302b0cb3c330270c1561981b867961986f78b6200c0bc3b0280ccf189c8bc3b0240ccf86e1b9302c0dc3b2302c0fc38a30ac0cc3aa30ac0ec39a30ac0dc3f36158178617c2f06218d687e1a5306c08c3c630bc1c864d61d81c8657c2b0250caf86616b18b685617b18768461a766911d6157187687614f18f686a1320cfbc2b03f0c07c270300c87c270380c47c270340cc7c2703c0c27c270320ca7c2703a0caf85e14c185e0fc3d9309c0bc31b6178330c6f85e1ed307c250c5f0dc3d7c2f0f5307c230cdf0cc33b61f85618be1d86ef84e1bb61f85e18be1f861f84e1dd30fc300c3f0ac38fc3f09330fcd4f0fcbd30bc1f860fc2f0a1d63ed2bf3fd3bf3fd7bfbfd0bfbfd4bf1febdf4ff4efaff4efaff5efa7faf737faf7b7faf7aff4efeff4efeff5ef5febdf3fe8df3feadfbfd1bf7fab7fff4efffebdfefd07fdfb8ffaf79ff4afeac75bde221b6f12544de920a636a7745c99ba8f2f669afd84aa0faa81fe9ffc166bbd40cfcb6f9ed61beaf98686de48cf3732d6d344cf3731f4223d5f64e84df57c5343bf52cf5f69e857ebf9ab0dfd163d7f0be809fdbf6cc1b23f4a6ba0a53cd0a4fee583d6506b0d406b24ab03adb1d61a8226dbb711689768ad3168976aad096809ad5d02da655abb14b442ad25402bd2da65a05daeb542d09a6aad08b42bb4763968576aad29685769ed0ad0aed6da95a05da3b5ab40bb566b5783769dd6ae01ed7aad5d0b5a33ad5d075a73ad5d0f9adec58266a0dda0b5e6a0dda8b516a0dda4b51b40bb596b378256acb59b40bb456b378376abd68a41bb4d6bb780d6526bb78226e70ab7694dd53369fb32cb683d1fb4db65ff06ed0ed9b7416b25fb3568ad659f06ed4ec85bb436b28f83d6566b52c7d5ffbae8783a88ab7d4b95abf5768d7bbde19ad57abbc7bfdea46a2f7b04555ea7219faee0554f1d8ff1798612cc3b4f07c947f402883f0069259df821ed94b0abb6a79b8ef7ac66b92ec6724590a69ba5fce920def2773778ba1bcc6a9bf4028ef8eb6ca7a4afb3359e72aeb30321ad59f7e498f965acb30f0387833a5beaeb6c8da79ceb6c39a435eb9e9cbf7d19ebec60e0705067bbb9a9b3a9a4afb3d97b264160af7b722df165acb3e38123fe3adbd9d7d99a4f39d7d9e720ad59f7e4baf6cb58672b8023fe3adbb59b3f37a8f194739d5d0f69cdba27f758be8c7576397038a8b3e5be9dadf194739ddd0969cdba27f7fbbe8c75762370c45f67bb3baab39d7c9d0db2fd5f4160af7b72eff9cb5867f70047fc75b6dcdf9fadf994739d7d1bd29a754ffa41be8c75f6a48eab7e868f743fc30da0fd4c6b3782f673addd04da2fb4763368bf84fe42d13e96be44d03ed1daada0fd4a6bb781f66ba3ef55699f6aed76d07ea3b53b40fbadd65a81f6575a6b0ddaefb4762768bfd75a1bd0fe5a6b6d41fb83d6da81f647adb507ed6fb4d601b4bfd55a47d0fe4e6b49d0fe5e6b25a0fd83d652a0fda3d63a81f64f5a2b05ed4f5aebac35d54f297d5fef6aad0970a583f8ea68023c9029cf984f43bca35b9e6411f0605e25f1e7d54995fdbc87ad3ea3ec25c0937250f604e451139e14f0748a9f27f38e5f69fcebcd6ce3a4e16902f24a42b93a3b28571ee425eb9679c9af0834dca73b5b18633fcf082fbcf2202f59b7cc770146d1b08d913657f61f758cf967e075b02f65ce33243f797759384a409734d7b7a862fb2f5a2b84ff637bdbc9d01cd5cb4cbd90bc64dd325f0a8c529e4e75cf98aa2963ca6074d546e4415eb26e9f77d576907807e0e9e688c76cd324ef6e7590771723ef12236f6c3b65aaeed8d605981d5c6f957c11d75b78fec070bd75455e555af3ba49dae15cafb73a1bcb315e6f35caabe270b03f64ea40378343e64bc0bbee11de7503ef24cdede09d8373cf8c775d0d1e994f018fb463a5c0d3a18e793a10e48de7b0b2ddf05a0acf035c6daf0e06a3ccdbb65717604c59181d9c13a6aa3b469600a368783f2ae9c8b3a8ed9a24c9dbc57525be4b21e7e6e6b54d01a4f93ff9d95fd556b6cf73ca96c27367996a7acd1bff764a2571ffa8098fe37da8c4517d4ce2fd9bbf04f1d635b35d32db9ba87b3caedaf2a4c123f3929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c523fd09f8dc96a4eb44c2683effe6ea3e7fe65b28b22efdabfa75de817e9df8fb2d5249ecfb93e7205a19652e80341fe555a5fdae8eab670ea49f0a9fb5329fbf72d96787cf63a6615ef2c367ad705b323cef541c5bded9efd2b8e86fbb3cc87e53c77cf6b393c55317cf3fa3a77986a7f81cf89d068faaa7ff915fc5e6a2ef2fd7be48f44ae271f6ed1505f6ba1eff76499dd7679d1f9cdf7ee071c6d5f33bd2564b7f793723ef0248f37b788e4a9ead92718692c672f8dc8fac5b9669057a7763dd4df5b2c2d1d0587f292c2b69fe086dea4aa8ab0edaca54aecfae63bf79fcc7e16c3f7e32079e0ec0e3a29d7174be91c47d20ee7e7cf3f934db798ca4c167fb1c3c5759edf34e929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c563f6b5e2fbb525248ca2397ef621d39fd15aaf4bd6affa7566e757e5ebba1f4efa9c5a1b65c67747cfe557a59da7e385c185cf3b446d4b57dfa788da96921f7e7ba603f0b8e8d7cd83bc64dd1d2d5e48bc38b6bcb3fdf8f17b5cd58f9f347c2db178ea6a7fc53e56f414f7d794c1837da351dff6e968688ef6f16aeb85e487fb5247d0248eef47bbd8ce782c319feb91fcb0fffa25ed6dd3c0d5b64f255db61bf8dd94747061fdc6efa96c86b66f8b8ee3331cf8ecc841cbff65aaae9f5afc5365ee157f9933dbf72ee04c433e98776f608d29ef12cc3b4f07c947f402881fc8af4a2be9c40ff15ad8d53e22df80417673b994b15c11a4e969297f3a88b7fcbd0c9e5e06b3da26dba09e1d84e3bfab36a9678447adc0234983e741ae9ec933db48f3f9467c6eaf919106cf5924cd4968a354596ccf8fda9e3974751c8b7ae6d0766edc0118cd329acf795eeccf697d03da8bb89fd3fa06d4217c4e2b30d6df1ad62f5c8d82e8638ba4f9b6b17ef39c5c96c1e7c024cdf7a0bdf8975a9c937f51d757b673725c2eaaec8a19bf83968e9119eb04b2e07982a479dfd866dd23b8bb5896fd286259f1cafc56586170a17f6ebeb396dde77b1965917add13ca22693e31ce01e33f6fc99e03bafaa61c9e7ba8f576b49455d2fc16f6b5dfc1399e6c27dc6fff6cf9bf4cd59d03e2788e7de22f7312f719d9be7d2c79f705d698f22ec175c939605fc3830288ff2768d3259da415af855ded23721e85ece672dd8ce58a204d6f4bf9d341bce5ef63f0f43198d536f903d4b33fc339a0abb6ba778447adc1234983f7146ddf01b5ddeba8ab7345f3fbc245c185f709f038e9e6bcc9fe9e90795fcd768ed0dae0c773847f83763661496bde2f94e3659ccf0de3bb12a590ef7f58f24dc7ec6757f02d0df3785ef045e6ede03be1997744f0bb82c280531ae2f8ed70592e1f185d7c6f3d119cff7de0cf62c46fb0cb720d80d1c536ccf5fbc4a5c028cb1500a38bf7bff01bf93561ec048cb82f0aa38bef92d6f67b8e78dddd081899deabc2fbc78d81d1c5b1abb6efd3e031b709fcba1a3b24990363476094e52e014617f7aff07ca3268c78ee22cb5d0a8c2eee33e73a060b7e1f1aefff08a38b73c05caf51f05e952c771930f670c4d83d07c61ec088f71c84d1c5f56402f2ad09634f60445e6174d0079061ec990323de2b97e52e07c6bb1c31f6ca81f12e6094e59a02a38bfbf909c8b7268cbd815196bb02181d5ceb67187be7c088d7c4b2dc95c09876c4d82707c63430ca725701a38bebf684c1f0598c7d8151f4ab81f16e478c7d7360bc1b1865b96b80f11e478c77e7c0780f30ca72d702e3bd8e18efc981f15e6094e5ae03c6fb1c31de9b03e37dc028cb5d0f8cf73b62bc2f07c6fb8151966b068c0f3862bc3f07c6078051966b0e8c0f3a627c2007c6078151966b018c0f39627c3007c687805196bb01181f76c4f8500e8c0f03a32c7723303ee288f1e11c181f014659ee26607cd411e32339303e0a8cb2dccdc0f89823c64773607c0c1865b962607cdc11e36339303e0e8cb2dc2dc0f88423c6c773607c021865b95b81b19f23c6277260ec078cb2dc6dc0f8a423c67e39303e098cfd2c8cfd1d313e9903637f6094e5ee04c601f13366be43d33f07c601c0f354fc3c19cf06e4c0f3945b9ecc379c0658f27a3afebc32db626050f3b23f0d3c83e2e7c96c8ba773e0118622580e3d1b1c3f63c6b34139300e069e21f1f3643c1b9c03cf10f06cb0c5b3a1f133663c1b9203e350e019163f4fc6b3a139f00c03cf865a3c1b1e3f63c6b36139300e079e11f1f3643c1b9e03cf08f06cb8c5b391f133663c1b9103e348e019153f4fc6b39139f08c02cf465a3c1b1d3f63c6b35139308e069eb2f879329e8dce81a70c3c1b6df16c4cfc8c19cfca72601c033ce5f1f3643c1b93034f397836c6e2d9d8f819339e95e7c0381678c6c5cf93f16c6c0e3ce3c0b3b116cfc63b621c9703e3780b4fdcdf171d67c96ba2a3b24f086a5e76612882e590719223c68939304e0246590efbd7273b629c9403e3646094e5b07f7d8a23c6c939304e0146590efbd7a73a629c9203e3546094e5b07f7d9a23c6a939304e0346590efbd7a73b629c9603e37460445e619ce188717a0e8c33804b96c3fef5998e1867e4c03813186539ec5f9fe58871660e8cb3805196c3fef5d98e1867e5c0381b186539ec5f9fe38871760e8c73805196c3fef50a478c737260ac0046590efbd7e73a62acc881712e30ca72d8bf3ecf11e3dc1c18e701a32c87fdebf31d31cecb81713e30ca72d8bfbec011e3fc1c181700a32c87fdeb0b1d312ec881712130ca72d8bfbec811e3c21c181701a32c87fdebcf38625c9403e333c028cb61fffa62478ccfe4c0b818186539ec5f5fe28871710e8c4b805196c36bae671d312ec981f159605ce2192f0a46e4298e8f278965c7bc9e2328fb73169ebcc04dd931afa504655faa7feb1be3b3f580717c3d60f43e7a46cff8e563f4fbb5f79189d1fbe87df48c9ed1337ac68b9db13eb4e19eb15ed4c7546d1915cfb2f879329e2dcd8167197826cb3de59631555b46c5b33c7e9e8c67cb72e0590e9e2db378e68031555b46c5b3227e9e8c67cb73e059019e2db778e68031555b46c5b3327e9e8c672b72e059099eadb078e68031555b46c5b32a7e9e8c672b73e059059eadb478e68031555b46c5b33a7e9e8c67ab72e0590d9eadb278e68031555b46c5b3267e9e8c67ab73e059039eadb678e68031555b46c5b3367e9e8c676b72e0590b9eadb178e68031555b46c5f37cfc3c19cfd6e6c0f33c78b6d6e2192be3f87ac0f86c3d60ac0f3e7a46cfc8c4e8f76bef2313a3f7d1fbe8193da367acbf8ccfd50346bfad3d232be3baf81953b932ae73ec99a37266c69f7a41af2bc66f22a494572f1a5ead35bc2a82342f807f2f3af02f0ff29575cbbce4972b734b02664779a7645ce4b5467ecf1a7ea869bdfe6d08fa78f0f4251d97b1e724fd73a04b9a597aa00f19d352261c93717dfce52da96edf96fc90672e194f67329e19643cabc9782691f1ac20e31943c6b3948c673819cfd3643c4f90f1b422e3b9878ca73d194f03329e0e643ca5643c7791f13c44c633998c6726194f3919cf3c329e11643cadc9780691f12c26e3e947c6f33019cfbd643cbdc978ba91f1b421e3e944c6338b8c673e19cf14329e95643c63c9789691f18c24e35943c633988ce749329e47c878ee23e3694bc6d39d8ca70f194f8a8c6736194f3b329ea9643c0bc878c691f18c22e36949c633848ca73f19cfa3643cf793f1a4c9787a90f12c24e32921e39943c6d3958c671a19cf2a329e3bc8782690f18c26e35942c6733b19cf50329e01643ccbc9781e23e379808ca72f194f4f329e45643c49329e0a329e2e643cd3c9782692f19491f10c23e31948c6f33819cf3a329e07c978ee26e3e945c6f30c194f1e014f22b8f09dd404fc7f1d68f9c6b28dc330ac45d5ff37683d1f96d9a8e30d2cebde00da4b3abed1b22cfab401ca92d6f1e4e79b323e615e699897fc0a81632309cf33643cbdc878ee26e379908c671d19cfe3643c03c9788691f19491f14c24e3994ec6d3858ca7828c2749c6b3888ca727194f5f329e07c8781e23e3594ec633808c672819cfed643c4bc8784693f14c20e3b9838c671519cf34329eae643c73c8784ac8781692f1f420e34993f1dc4fc6f328194f7f329e21643c2dc9784691f18c23e35940c633958ca71d19cf6c329e14194f1f329eee643c6dc978ee23e379848ce749329ec1643c6bc8784692f12c23e3194bc6b3928c670a19cf7c329e59643c9dc878da90f17423e3e94dc6732f19cfc3643cfdc8781693f10c22e3694dc633828c671e194f3919cf4c329ec9643c0f91f1dc45c6534ac6d3818ca701194f7b329e7bc8785a91f13c41c6f33419cf70329ea5643c63c8785690f14c22e3594dc633838ca73319cf5c329e8e161e07e33b6678e4fd3c59b7ccaf23c9dbc176c88c6bf9b2a3326dd2eb6aa8d72bfc925f01a4f9b071f6b76990ad0fa20bd77a1dc7ba21de6c028f36392a8b6c8f3c63fb38ce3b85ef8d06c01018fe04161e17efdb3a2ae779f530eef155371b5e99dbae08d2bc0cfe6d76e09fad6ecbbce4972b734b0266ac17c541bcf5e295f8cbf4ffc76d155f5f31fcc572bdaae331d6cba45ac716bdae8690dfab90ef361dcf8b315fb5aead7a5d32ceac706c035dd2fc33b4cbc8ac26697ff19b66db753c1d1f73661c6c1c47573cc1290df1edc0b3d5018fa37266b6cd0ea34ceb8c3215419a2d50ce1d0eca9907f9caba657e07f0c8d411785cd4839a6cf3a8b18719783a93f1cc20e3594dc633898c670519cf18329ea5643cc3c9789e26e379828ca71519cf3d643cedc9781a90f17420e32925e3b98b8ce721329ec9643c33c978cac978e691f18c20e3694dc633888c673119cf16329e7e643c0f93f1dc4bc6d39b8ca71b194f1b329e4e643cb3c878e693f14c21e35949c633968c671919cf48329e35643c83c9789e24e379848ce73e329eb6643cddc978fa90f1a4c8786693f1b423e3994ac6b3808c671c19cf28329e96643c43c878fa93f13c4ac6733f194f9a8ca70719cf42329e12329e39643c5dc978a691f1ac22e3b9838c670219cf68329e25643c43c9780690f12c27e3d94cc6f31819cf03643c7dc9787a92f12c22e34992f15490f17421e3994ec633918ca78c8c671819cf40329ec7c9781e24e3b99b8ca71719cf33643c79043c51630fcbff378326efd4e178c43b757c2b68f9963ce459f81da015e8b8ac43bdca39bec585eb469f5cbd478879a5615ef2c3b1877792f03c43c6d38b8ce76e329e07c9781e27e31948c6338c8ca78c8c672219cf74329e2e643c15643c49329e45643c3dc978fa92f13c40c6f31819cf66329ee5643c03c8788692f12c21e3194dc633818ce70e329e55643cd3c878ba92f1cc21e32921e35948c6d3838c274dc6733f19cfa3643cfdc9788690f1b424e31945c6338e8c670119cf54329e76643cb3c97852643c7dc878ba93f1b425e3b98f8ce711329e27c9780693f1ac21e31949c6b38c8c672c19cf4a329e29643cf3c9786691f17422e36943c6d38d8ca73719cfbd643c0f93f1f423e3d942c6b3988c6710194f6b329e11643cf3c878cac9786692f14c26e379888ce72e329e52329e0e643c0dc878da93f1dc43c6d38a8ce709329ea7c9788693f12c25e31943c6b3828c671219cf6a329e19643c9dc978e692f174ac1b9e52f52e1e8ef7295c38a521be0378b638f0c7513993f81e669c63692aaf76195e6d36bc2a8234dbc1bf5d0efccb837c65dd322ff97966cf1cc5ac78e4d970dbfbc14b481845dbe294a734998032cb545dfbb80b785c1c3f1cf99e69c7761b655a62f15dd2605dddeda09cb67d47e6775bf22e0ee2f5624f0dbcd863e1d953c75e487eb9326faf87ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e0781f7d9fbec7d4e7ebec9fbace3de67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e473133f8ac7896eab8b02620dd521246d176b8e5c9bc6fb434387fca33e6d310df033cbb1cf8e3a89c9967c8f71a655a1a5ce8bba4c1fd6baf8372daf61d99df0bdb2117e6ddf590d9fb5c3b66c5b34cc797eadf04a45b46c228da2eb73c99766c5970fe545d3bb617785cb4f38eca9969c72a8d322db3f82e6970ffaa74504edbbe23f395b01d2a3db367b6302b9ee53a2eac0948b79c8451b43d4e795299f71b9707e74fd5b56395c0e3a29d77e47ba61ddb679469b9c577498375759f8372daf61d9997fc7265de5d0f99bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866eff3c5e3b3e2916f260b6b02d2ad2061146daf539e4e997e8715c1f9539e319f86f83ee0a98c9d27dbefe0c0f74cbfc37ea34c2b2cbe4b1adcbff63b28a76ddf91f9fdb01dbeecccbbeb21b3af1b75c3eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c73143343dd503c2b755c5813906e2509a368956e7932df3d58199c3fe519f36988ef079e7d0efc7154cecc733b078c32adb4f82e6970ff3ae0a09cb67d47e60fc076f0cc9ed9c6ac7856e9b8b02620dd2a1246d1f6b9e5c9b463ab82f3a7eadab103c0e3a29d7754ce4c3b76d028d32a8bef9206ebea4107e5b4ed3b327f10b68367f6cc3666c5b35ac7853501e95693308ab6df2d4fa61d5b1d9c3f55d78e1d041e17edbca37266dab1434699565b7c973458570f3928a76ddf91f943b01d3cb367b6312b9e353a2eac0948b7868451b4036e7932edd89ae0fca9ba76ec10f0b868e71d9533d38e1d36cab4c6e2bba4c1ba7ad841396dfb8ecc1f86ede0993db38d59f1f4d771614d40bafe248ca2e1f9cf91f8794a13068f9aaa6bc78e38f6c7513933edd8d1c0eefb11f05dd2605d3deaa09c7990afac5be68fc276c88579773d64f63ed78e59f10cd471614d40ba81248ca21d069e63f1f394260c1e3555d78e1d73ec8fa37266dab1e381ddf763e0bba4c1fdebb88372e641beb26e993f0edb2117e6ddf590d9fb5c3b66c53348c7853501e90691308a7614784ec4ce93fdbe31f2a8a9ba76ec84637fdc9433db8e9d0cecbe9f00df250dee5f271d94330ff29575cbfc49d80e9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99b99915cf101d17d604a41b42c228da71e039153b4fb6df0179d4545dbfc329c7feb82967b6dfe17460f7fd14f82e69b0ae9e7650ce3cc857d62df3a7613b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563cc3745c5813906e1809a3682781e7b5f8794a13068f9aaaeb7778cdb13f8eca99e9773813d87d7f0d7c97345857cf3828671ee42beb96f933b01d3cb367b6312b9e113a2eac094837828451b4d3c0f37aec3cd9fe53e4515375edd8eb8efd7153ce6c3b7636b0fbfe3af82e69b0ae9e7550ce3cc857d62df367613be4c2bcbb1e327b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccdee78bc767c5334ac7853501e94691308a760678cec5ced329993078d4545dbfc339c7feb82967b6dfe18dc0eefb39f05dd2e0fef5868372e641beb26e997f03b6c3979d79773d64f675a36e987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e6266a81b8aa74cc7853501e9ca4818453b0b3c6fc6cf539a3078d454dd733b6f3af6c7513933cfedbc15d87d7f137c9734b87fbde5a09c7990afac5be6df82ede0993db38d59f194ebb8b026205d3909a3686fb8e549250c1e3555d78ebd053c5f899f27d3aebe9503cf5780e7edf8794a1c9533a9d6fb55608f6bbdcaabaf195ebd657855046990e16b0efccb837c65dd322ff97966cf1cc58c6da1b02620dd9b248ca2bd0d3c2eda0d55f6367a5db2fe8661e8d7b42adf73f1e75b8ad72c0df57a8543f22b8034e9e655699fd26c85f07fd96eaa3c670dcdd1b76f4a6cef4bc8bce45718d4d93544b5d734e8858be7fc733dee9fb5f0fc253e9e24eee798978b6f2be5facec5190b4f8c652f897adfc4c577ec54d9dbea75c9fad53e3ab1a953cf4b71df93f6a3ad51e602487303b41f53a1fdb0b515aef7cdbcc0be6fe60755ed9970156bddbc37f117ad4bba73901edb9cfefa17f7cffe505657ed62d43509b68b66dbedd27bf3fe98997711f8728ed433db751cfa38d0c23d90801beb635dee67b26edb3d8481868f6c9ee1b63e67f17190857b100137e37e3dc8f091cdb3cfdaaf8758b887107033eed7430c1fd93cfbacfd7a98857b180137e37e3dccf091cdb3cfdaaf4758b847107033eed7230c1fd93cfbacfd7a94857b140137e37e3dcaf091cdb3cfdaafcb2cdc6504dc8cfb7599e1239b679fb55f975bb8cb09b819f7eb9af69332edd78eee7f67fa49d133355577cff09c537fb2dfabcfe5f993d781c7459d72540f928eeeb966fa49cdf107ce195ee1f8038eefcb56fb5d22c9cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f33bedf8bfd2b92ee0d1246d11c3f9b9fe9cf68a7d725eb57cffeceb8c265bea924f67bca73c9264701a4f9d3f55569e76836ec5fc47ed13386e6725b9ae34fcbbce45708e5c1faefea5deda8baf58625efe2d8f24e95bbf13895bc3c5cc72541d5767ecd280f7a7a3af6fccff734cff0f4b4e3bc737d5f02791cf4c596382a67a62d386594c9f4b808d2b484729e7250ce3cc857d62df3a78047a67ce0715507038327b0f823d35c329ece643c93c8788693f1dc42c6f30419cf35643cf790f15c42c6b3988ca703194f7b329e99643ce5643c83c8786e20e379988ca729194f6f329e02329ef9643c9dc878da90f1d4c53d805c78a690f18c24e3b98d8ce749329e3bc978ae23e3b98f8c2741c6d3968ca73b19cf6c329e71643c43c8786e22e379948ce74a329e34194f23329e85643c25643cd3c878ee20e3194dc673968ce776329e01643ccdc8781e20e32924e3e949c65341c6d3858c672219cf30329e62329ec7c978ae26e3b99b8ca70919cf33643c1dc9786690f18c21e3799a8ca70519cf43643cadc8782e27e3b98b8ca70119cf3c329e52329ec9643c23c8785a93f1dc4ac6d38f8ce75a329e7bc9782e25e3e946c6338b8c672c19cf60329e1bc9781e21e3b9828ca70f194f43329e05643c29329e76643c53c9784691f1b424e3e94fc6733d19cffd643c9791f1f420e39943c6d3958c670219cf50329e9bc9781e23e3b98a8ca72f194f63329e45643c49329ee9643c65643c03c9789a93f13c48c65344c6d38b8c278f8027115cf82d9d04fcff75d0e49b2ff8bdb07ccbfaa49f51d2abe3d0cc1617ae3bdfb2eed31606f4e9249425ade3c9cf379df79d9b3cbd5e9997fc0a81e334094f2f329e22329e07c9789a93f10c24e32923e3994ec69324e35944c6d3988ca72f19cf55643c8f91f1dc4cc633948c6702194f57329e39643c3dc8782e23e3b99f8ce77a329efe643c2dc9784691f14c25e36947c69322e35940c6d3908ca70f19cf15643c8f90f1dc48c633988c672c19cf2c329e6e643c9792f1dc4bc6732d194f3f329e5bc9785a93f18c20e3994cc6534ac6338f8ca70119cf5d643c9793f1b422e379888ca70519cfd3643c63c8786690f17424e379868ca70919cfdd643c5793f13c4ec6534cc6338c8c6722194f17329e0a329e9e643c85643c0f90f13423e31940c6733b19cf59329ed1643c7790f14c23e32921e35948c6d3888c274dc6732519cfa3643c3791f10c21e31947c6339b8ca73b194f5b329e0419cf7d643cd791f1dc49c6f32419cf6d643c23c978a690f19c21e36943c6d3898c673e194f01194f6f329ea6643c0f93f1dc40c633888ca79c8c6726194f7b329e0e643c8bc9782e21e3b9878ce71a329e27c8786e21e3194ec633898ca73319cf5c329e7c8307ffafde3592ebb353fab700febf583f8cd254af4bd2c83b89eaded2094353e53deea8bc2782aa290df3c7a1bcc27e02784e38e23969f0987917427c207876ccd014e351478cc70c46993f0a8ce2df31e039e688e7b8c163e65d08f141e0d91143538c871d311e311865fe30308a7f4780e788239ea3068f997721c4878067870c4d311e74c478c86094f983c028fe1d029e438e780e1b3c66de85101f069e1d3034c5b8df11e3018351e6f703a3f87700780e38e23968f0987917427c0478b6cfd01463a523c67d06a3cc5702a3f8b70f78f639e2d96ff0987917427c1478b6d7d014e31e478c7b0d4699df038c953abe1778f63ae2a93478ccbc0b215e069eed3634c5b8cb11e36e8351e67701a3f8b71b78763be2d963f098791742bc1c3cdb69688a718723c69d06a3ccef0046f16f27f0ec74c4b3cbe031f32e84783fd084b72b68db75bc0b68db74bc33685b75bc14b45775bc13685b743c05da2b3a5e02da66f103b44d3ade11b49775bc03681b75bc1b681b74bc3b682fe9780fd0d6eb784fd05ed4f15ea0bda0e37781b64ec77b83f6bc8ef7016dad8ea7415ba3e37d415bade37783b64ac7ef016da58edf0bda0a1dbf0fb4e53a7e3f68cb74fc01d096eaf883a03da7e30f81f6ac8e3f0cda121d7f04b4f13afe28684fe9f863a0bda9e38f83f6968e3f01dadb3afe24685fd1f101a07d55c79f06ed6b3a3e18b4afebf850d0bea1e3c341fba68e8f04ed1d1d1f0ddab7747c0c68dfd6f1b1a07d47c7c781f65d1d9f00daf7747c2268dfd7f149a0fd40c72783f6ae8e4f01ed873a3e15b41fe9f834d07eace3d341fb898ecf00eda73a3e13b4f7747c1668efebf86cd03ed0f139a07da8e315a07da4e37341fb998ecf03ede73a3e1fb45fe8f802d07ea9e30b41fb58c71781f6898e3f03daaf747c3168bfd6711cf7ee373a5e1cc4dbbe7f1a544dc590b7e4a7d2fc56c71b196964d90248d350df1c55f73b8a82aaf65f8e074a93f67f3b68d2fe6f034ddaffada049fbff2a68d2fe6f014ddaff574093f67f3368d2fe6f024ddaff974193f67f2368d2fe6f004ddaff974093f67f3d68d2febf089ab4ff2f8026edff3ad0a4fd7f1eb4b48eaf054ddaff35a049fbbf1a3469ff578126edff4ad0a4fd5f019ab4ffcb4193f67f1968d2fe2f054ddaffe74093f6ff59d0a4fd5f029ab4ffe34193f6ff29d0a4fd7f133469ffdf024df6b54f419363c2dba0c931e12ba0c931e1aba0c931e16ba0c931e1eba0c931e11ba0c931e19ba08dd6f177409363c2b7409363c2b7419363c277409363c277419363c2f7409363c2f7419363c20f409363c2bba0c931e187a0c931e147a04dd7f11f8326c7849f8026c7849f8226c784f7409363c2fba0c931e103d0e498f02168724cf808343926fc0c343926fc1c343926fc02343926fc123439267c0c9a1c133e014d8e09728c68029adcaf5653f2734e4541d5940f7909533a88f79883531ae2cf40d9655a43c6730b19cf66329e6bc8782e21e3694fc6534ec6b3948c671019cf8b643c3790f17c4ac6b38d8ca72919cf21329e83643c05643c6dc878ce90f1ec24e3798b8c671519cf6d643c7792f15c47c6f332194f828ca72d19cf10329e75643c3791f1bc4ac6732519cf01329efd643c8dc878de26e3b9838c670519cf59329edbc9783690f13423e32924e31946c6b3968ca7988ce715329eabc978f691f15492f13421e33945c673928c671919cf7a329e16643cadc8782e27e3d94ec6d3808c6704194f6b329e5bc9785693f16c22e3b9968c672f19cf1e329e4bc9784e90f11c27e379818ce746329ead643c5790f13424e36947c6338a8c6725194f7f329e8d643cd793f1ec26e3d945c6731919cf31329ea3643ccf93f1dc4cc6b3858ce72a329ec6643c65643ccbc9780692f1bc44c6d39c8ce757643c3bc8788ac8788e90f11c26e3c923e0490047009afcbf0168f2beee59d0e4bdde33a0c93bbf3b419377821783b6d0a2e55bf884e113d0e45d918f4193fb0f8b409367f47e099a1ca7257f35bfa0c585fcf9967236b0f02fb294f363cbb2b8bd65997410eff6c6bcd281fddb1c7906e317cd73988ce708194f1119cf0e329e5f91f13427e379898c672019cf72329e32329ec6643c5791f16c21e3b9998ce779329ea3643cc7c8782e23e3d945c6b39b8ce77a329e8d643cfdc9785692f18c22e36947c6d3908ce70a329ead643c3792f1bc40c6739c8ce70419cfa5643c7bc878f692f15c4bc6b3898c673519cfad643cadc9784690f13420e3d94ec67339194f2b329e16643cebc9789691f19c24e33945c6d3848ca7928c671f19cfd5643caf90f11493f1ac25e31946c65348c6d38c8c670319cfed643c67c9785690f1dc41c6f336194f23329efd643c07c878ae24e379958ce726329e75643c43c878da92f124c8785e26e3b98e8ce74e329edbc8785691f1bc45c6b3938ce70c194f1b329e02329e83643c87c8789a92f16c23e3f9948ce706329e17c9780691f12c25e32927e3694fc6730919cf35643c9bc9786e21e35943c6936fe139eb8847fab265dd327ff64b9ef77123efe31749de478dbc8f5e24791f36f23e7c91e47dd0c8fbe04592f77e23effd1749de9546de951749de7b8cbcf75c2479ef32f2de7591e4cd7cdea2be47d15fc74fe9df04fc1fbfe379c611e3598351e6cf00a368380e477f473c51e73cfd09f2565e0cd47179d72601ff1f088caeea547f8351e66d750abf8b3dd0114fd4b9da4082bc951772cf48de0d4fc0ff0701a3ab3a35d06094795b9d3a0a3c831cf1449d630e22c85b79217de4f2eda004fc1fc7857555a706198c326fab53f81db4218e78a2ce8d8710e4adbc90673aa5ef2301ff1f068caeead4108351e66d75ea20f00c73c413754e3f8c206fe585bc1325cf5625e0ff38ce8dab3a35cc6094795b9dda0f3c231cf1541a3c95162fbea8bc9517f24d817dfa3701ffc7efe0bbaa53230c4699b7d5a94ae019e58827ea1a6a1441deca8b321d97777b13f0ff32607455a746198c326fab5338ce4d99239ea86bbf3282bc9517d26726dfa249c0ffcb81d1559d2a331865de56a7f0bbfce58e78a2ae59cbeb20efa8ebafbac83bea5aa22ef28e3a2fae8bbca3cef1ea22efa8f395bac8bbd2c8bbb20ef38e3a8ed445de516da2dfbffdfe1d77de5fe4b1a4d2c8bbb20ef3fe22f7ef2fb24dfd22db167fdee2dbb5bacadb9fb7709fb7fc25bebc93787dda24c6f5e27d811dfa17efed6c074deeb56c034dee976d054dee79be0a9adcb7de029af43dbc029af41fbd0d9af40162dfa4bcb371123479260dfbc4648c89e3a0c95814d817f30b1d3f0ada021dc73e80f93a7e18b49feb38de7bfe998e1f046d9e8e1f00ed231ddf0fda5c1ddf07da873a5e095a858ee33d9e393abe07b40f741cef2dbcafe3bb409bade36f81f69e8e7f0ada2c1d2f07eda7166da68e6f066d868e6f02ed273afe32683fd6f18da04dd7f10da0fd48c75f026d9a8eaf07ed873afe22685375fc05d0a6e8f83ad0ded5f1e741fb818eaf056db28eaf01edfb3abe1ab4493abe0ab4efe9f84ad026eaf80ad026e8f872d0beabe3cb40fb8e8e2f056d9c8eff0ab46feb781968f93a3e0ab4063a3e0234790f671868f26dd521a0c9fbe58340936fd00f04ad898ef7074d9e95c6316ae47b8e38468dbcb38963d4c877af178126dfdac0b167643c0e1ca346be01f60bd0e43d9605a0c9b75be78376a58eff1c34f9c6fdcf4093efd8cc034d9ec5fe0834f91ee25cd0e41dcc0f4193ef46578026dff298035a731dff0034f9a6d7fba0c97b20b341936fb1be079abc6f3d0b34f966fd4f412bd6f199a0dda2e33340bb55c77f02da6d3afe63d05aeaf874d0e4db1c3f024dbeff300d34f9a6da0f416bade3534193774ba78026efc3bd0b5a5b1dff0168f2dde3c9a0c9bb08df07ad838e4f02ada38e7f0fb4a48e4f04ad44c7278096d2f1ef82d649c7bf035aa98e8f03adb38e7f5bffaafd4fed97afebf97410dff994caef5c70fe9467cca7212e0cc813e7395611f0605eafc55ef654529553daaf7cbd5ea92faf41dea762cf3b99c9fbb45e57815eef2923ef0248f33fafafda3627b4d6402f77c6580eaf8165ddb24c3bd04f1aeb6eaacb7bda51794f194cc28d3e489a7fd74cea58b64737a08e9e7d4ba97d40ea5a001ee29486b830b8f12a95c4f3ed9af09c069ef8f7936489ab3a81fb569c6d88ed1e9059d78a20cd29f0efa403ff705f9775cbbce4e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1487f02f68f4bbad7491845c3beaed3f1f324b1cf55d6affa755e847e1dd7fd7b0df57adb1b652e8034ef37ab4abb51c70be1ffb2dda2b6a5837ec26ab7a5e45708e5390d3c2efa8bf3202f59f76b162f245e1c5bdea972371ea792ea3913d5c76e3ee3f6bac55357fb2bf6dda2a7b8bf9e3378b06fb41078dfd0bf0958cf1b500607fb78b5f542f2c37de935d0247e0e185d6c673c96487bd04ecf63dfb4a439aabd957ef1f8b77d2ae9b2dd3801654a0717d6ef0248730adabed7741c9f0d791d7c7bc7f27f99aaeba716ff54998fc55fe6243e032fdbf79825ef23c01a53dee73d7f9fa783e4237a01c4bfd9ac2aada4133fc46b6157fb883c3b8bece672e78ce58a20cd714bf9d341bce53f66f01c3398d536390bf5ec1d38febb6a938e4778d40e3c9234781ee4ead879c6e0110ec90fdbd146461a59b600d2bc0b6d942a8bb4f352cea86380ebe398acdb761c338f0b094b1955fd98714515efc5fefcd727d05ec4fdfcd7275087f039adc0587f7b58bf70350aa28f2d92e637c671d4c535066e4bd34ff459d2fc1edaa16bf4c3b8b99ceb7f51d76d51e7fac71df02482f3afbdd554ddf11d8f31271cf0382a67d276ec3a6994a908d2b484723a388fa9f63dc26390b78b6d8e5ec839d429c38b0248f3df8cb623ca47bc563d5d27654959cf07db5bca2269fed568a78e3a6072b9dd8e4099d47a5fb39455d2fc3bb47fff17cee7653be171f8b2e617fe5fa6eada03f14f95f950fc654ee2bb9fb27d0f59f23e00ac31e57dde7ba772be2ff9885e00f144f3aab4924efc10af855ded23f26e1bb29bcb9d32962b8234872de54f07f196ff90c173c860cebc87d4bc2a2ef5c865bb7938c2a3f6e091a4c1fbc7726cc7f71b6df7b55c7d7b35eabc19bfbd2a1ab6cfd780a72e9efdb65db398f7506de783ed0d7e3c1f6cae999b06e7bf8f836dce8b6e9ff92fc1f75c03284760943530d81cf95c8a3e9bf700db826efa2cffb35d33b4049febe2feb4709bd702783d22dce67106af47ee046e55ef653be17d44d1ded4bf8ecec94bf17a4b8e31e63939de47eb08ecb8ac70bd61298b782069f3e1fff2bfbf04f6eb93cf5ace8c9f359651febe69a4b3e5d304968ded5d8d9264d2e43f637062db2ce96cbeca7e80754ed665ee2b785f54d2f436da2433addaf6139b56f923db51bcc3f604eba4abfb4851dfea96fc14a3dc03c2ef9bbbb88f92ebfb53786fc545dbeea88d4ee2bd8bf8beffd07d8ced9ecbeb865745c185f7335cb6e951e723a72c79c7e7456aacadbfdfe6455df6f77fd63dcd26463c9ebcbb94dbda399b17272c3c2eeebf54e7c5094bde317a31de764fc4e6c5710b8fabebed282f8e5bf28ecf8baed6fb55362f8e59785c5d77457921f9e5ca7c8280b989118f27efd231785faa3a2f8e5a78e2bf2755bd17472d79c7e7454997eafa3fd18b23161e57fd98515e1cb1e41d9f17ddbadbee5fd8bc386ce1395cc75e1cb6e41d63bd1867bbbf64f3e29085c7c1bdc66abd3864c93bc6f3c32e78afb13a2f0e5a780ed6b117072d79c7e84599ed3ea8cd8b03161e57f741a3bc3860c93b3e2fc6745679efaf8117fb2d3cfbebd88bfd96bce3f3a2ac9bca7b5f0dbcd867e1d957c75eecb3e41de33554a65e54d6c08b4a0b4f651d7b5169c93b3e2fc666ceb5f6d6c08bbd169ebd75ecc55e4bdef17991cc1c53f7d4c08b3d169e3d75ecc51e4bde31d68bccf5e4ee1a78b1dbc2b3bb8ebdd86dc93bc6e348a65eecaa8117bb2c3cbbead88b5d96bce3f3627ce6fed3ce1a78b1d3c2b3b38ebdd869c93bc67b2e997ab1a3065eecb0f0eca8632f7658f28ecf8b4e9963eaf61a78b1ddc2b3bd8ebdd86ec93b3e2fc665fac4b6d5c08b6d169e6d75ecc5364bde319e7766da8bad35f062ab85676b1d7bb1d592778ce79d99fb17afd6c08b572d3cafd6b117af5af28eb1edcc9c776ea981175b2c3c5bead88b2d96bc633cefcc78f14a0dbc78c5c2f34a1d7bf18a25ef18cf3b33c791cd35f062b38567731d7bb1d992778cf522d3766eaa81179b2c3c9bead88b4d96bc63bcaf95693b5fae81172f5b785eae632f5eb6e41de3f548e61edfc61a78b1d1c2b3b18ebdd868c93bc6bea2cc39f8861a78b1c1c2b3a18ebdd80079bb7a5f47f29067b1da185e14409aff6c3c8b15e5a3ac039f2bc3b2bc147b59b2cf95ad8f28cb4b501649f33f8c67f9d63b607254d64c9d7911caa4d67bce525649f3bfe099e17f8367cf659bbc01be5dd2e2c2ffcb54dd3348e29f2af3baf8cb9ca9abcf03671af2c1bcd7026b4c799760def26cbae4237a01c49bb4a84a2be9c40ff15ad8d53ef2828e23bbb9dc0663b92248f382a5fce920def2af3378d619cc99f71ea09e493d72d37665995e88f0a80d782469f099bd371cf19c33788443f2c3e70c1b196964d902487385f6509edb95e720a59c51cf483a68cbaa7d4652f2c3678b5f0346b38caa7ef483673f3b6abd4350a5950837aca7d4d054593b3b2aabe425eb96f9cec028635294d63d63aaa68c9d0c46c5d3d5816738ce864cd51d2fba024f17073c8eca99390e7533cad4d9285311a4c1771bbb3928671ee42beb96f96e90b78b6d8e5ec831f90ec38b0248d311dab3ea7c9475a8fa5b6a294b4fc76591754bbbd4b30ef2ee6ee49d32f24e04e76fe720a87effea0ecc3d1c30abf5f68a7fbd99fdeb2ebd2ea953924f0acad41b3c88ab4c98b79ce7493ea21740fc5e38cf9374e2871cbf845dd565d996c86e2ed7d558ae08d2f4b4943f1dc45bfe5e064f2f83596d93ee706ee7607fc8d4819e0687cca7c0bb5e11def504ef240d1eff4a1d79d7c3e0e961e4ad78e41ca71b6872ae20fc09f87fb20eb8cd76af9b855bb4eec0683bd7e9143f63b5e73a9d8051b41ec0d3dd9167e6b6bec3f0078fcb8d8c34b26c01a41902c7c68425addaeffe19ca256317c638ce4fa64d6fe4c02f1c5731007f02c3c300fc92723674c073695035b6e29c8a19b3cb268ceb3f2edbf52868050626fee6598a910f1ac61b58b420387f08c902d06408c986a0e51bb6e0d095925e86b4736117fa21eb2e30389b004b9c79e3f09b325557751a038f8baaacaace657a5dbaea0c9a3da9621cd68f8606676dea8efa5f836ad245adcbd57630f78934cc9b75b0c051fe0da0bc699897fcd4b629d4f19965e553face9e3077dab8e91573d02873c7c6785e70fe06307fa30c77b5d36105c00263e3d0d028173618f23fd93097c6cf598a63dc9ade04909f4c97826f9738f04dad5fc6aa2d2f9b3ab5dfdc31532795df3f777a79c5a419d3716b36319c8bdad2f2ff46a0d99a784cab266cb670d9c616cd36e1a8c04d409323d725a009cfa5a03580b8a437b78c93eada12d62fbb94fa9f32a7a12e78e3a0aa0ac8e158b5ab6aff55a7729707d953a12b82ece654430daba185d550c26ae8603554b01ad1527dd542dd7556674f6a685f3594af1aba570dd55b1c6487e2bd35a81a6a574def02e7ed41f6544b0d9ddb3ac80e8dab6e57aad7d5d5a7ddd4a734d429bbba15a04e73d5659dba0451a79dea7453ddb250b7afd4699c3a4556a77fea944d5d82a84b0f75a9a82e9dfa68affb86e1ee30dc13867bc3705f18ee0fc3036178300c0f85e1e1303c128647c3f058181e0fc31361e817862783ec50d203c2f054901d6afae9203b0cf5e0203b44f5d0203b7cf5f0203bb4f5c8203becf5e8203b24f698203ba4f9d8203b4ceef8203bd4eec4203b5cefe4203b34f0d4203bbcf0f4203b94f1cc203b1cb21a3a590dbdac866456c337aba19ed550d16a08e9854176686a35ecf4e2302c09c3b361782ec80edbbd2cc80ef3ad86ff5e1964870b57c388abe1c5555782ea42515d0beab6bdeabe52b796559796bae5adba6255d7b4eaaa578f2ea84739d4a32dea511ff5e8937a144c3d1aa71e15548f4eaa4749d5a3b5ea5163f5e87565907d347f7f907d7543bdcaa25eed51af3aa957bf8e06d95703d5eb9dea7549f5faaf7a1dfa7490bd9dad5ead575d9cea16b7ba95ad6eebabdbee6a68f9b7c3f095307c350c5f0bc3d7c3f08d307c330cef84e15b4176f8e1ef04d9218cd510c8df0fb2432babfaa8866cfe51901d0afa27417688e9f782ecd0d51f04d921b13f0ab2436dab21b8d510debf0cc3c74176d86f35fcf9af83ec90f6bf09c36fc3f05761f85d187e1f86bf0ec31fc2f0c730fc4d18fe360c7f1786bf0fc33f84e11fc3f04f61f8535035f4353616bfd333b7e8f9b28a8a71d366561457cc289e36776ac5a499531716cf9f5431b178c6bc71b3c74f9d311f175eaf9b2719b7bbefecd9650b8b274d1f3b6e41f18cb915c533c6178f993177fad8f30ed427f442375c9863d9d8b1d1997d3dff73907eab9699bea7979311d11faabe6c1fd6c6908f6bb3d0ffae658166eaa397dc3e19903dd72d9e3375464571b2787af8373cb8ce983f6e6c8762fcdf9cd0e43915c5732aca6657148f9f3d635a7149075cef078d6b51883f35760353704dedccf9573d9672adaad89166b570e007cd6a47fa71b3cf41fa692d33fdafb529e1bfd466a166cd6b47785bf3485be6cc1d5331bbacbc227ae1d69f67e10ecd6b51ccbb6a59cc3fd726b3ff5e9b859ab6a81d618716b5c86c700e9905ff0f4017f891c0fa04009b2d6c6f00000021291f8b08000000000000ffed9df7771c45b6c77b64490e638de51c018171906549a3916c598e12b08071029b60927192c1605bc61669030b1b6161173692173647364736e765132cbb0b0bcbe665c30fef0f78efbcc379b77aea3e7d55aed6d1882e71dbdc3ee7baabbfaae9fad4b76fd78cab7b7a725179f93745ce96c750cc8f8e5df8efdd765d7c694b5b8afb2a86e4cc6584b32a239c6332c2599d11ce9a8c70d66684736c4638c76584737c4638276484339f11ce8919e1accb086721239c9332c2599f11cec919e19c9211cea919e19c9611cee919e19c9111ce9919e19c9511ced919e19c9311ceb919e19c9711ce1332c2796246384fca08674346384fce08e7292972360127cf859f6ad70bec7aa15d2fb2ebc576dd68d74b6c1fabedb6d9e7528a668a16e76fad8699c24c8a979cbfb55374502ca3586effd660ffd649b182a28b6225c52a8ad5146b28d652acb39ef4509c46713ac51914afa23893e22c8ab329d6539c43b1816223c5268acd145b28cea5388f622bc5368af3292ea0b8d061b988623bc5c51497505c4a7119c5e5143b28aea0d849b18b6237c51e8abd14bd14fb28aea4b88a623fc5d514d7501ca038487188a28fe230c5b51447288e52f4535c4771bde3d90d143752dc44f16a87f33514afa5781dc5cd14afa7b885e2568a3750bc91e24d146fa6780bc55b296ea3b89de26d147750dc49f1768a7750dc457137c53b29de45f16e8af750bc97e27d14f750dc4b711fc5fd96854f8407281ea47888e2fd140f533c42f1018a0f527c88e2c3141fa1f828c5c7283e4ef1098a4f527c8ae2d3148f527c86e2b3149fa3f83cc51728be48f1258a2f537c85e2ab145fa3f83ac56314dfa0f826c5b728be4df11d8aef527c8fe2fb143fa0f821c58f287e4cf1138a9f523c4ef133c7f39f53fc82e29714bfb2da1376fda45dffdaae9fb2ebdfd8f56fedfa7776fdb45d3f63d7bfb7eb67edfa39bbfe835d3f6fd77fb4eb3fd9f59fedfa2f76fd57bbfe9b5dffddaeff61d72fd8f53fedfa5f766dae8fe52797cbe3a281a53b4a69cce9e8ed32f3e36ca67bfdcd5cdb1963ffc6eb06ab57db6d5ee7ac5e63b76b1cbdd66ed73afb1967b7c7397ac16e171cbdde6ed73bfa14bb3dc5d1a7d9ed698e7eb2dd3e19f4bcfd5bb963e595d1c65829071ae75f156835561b035a2def0eb4b156ab018d8f6f2d68e3ad3616b409561b075ade6ae3419b68b509a0d5592d0f5ac16a13419b64b53ad0eaad5600cda6663409b42956ab076daad5268336cd6a53409b6eb5a9a0cdb0da34d0665a6d3a68b3ac3603b4d9569b09da1cabcd026daed5668336cf6a73403bc16a73413bd16af3403bc96a2780d660b513413bd96a2781768ad51a40e3f3f264d04eb5da29563339c5e35cfc1aab5781762a9fcba02de0f318b4857c0e83b688cf5fd01643dbac35f2f90cda12ab713e9bbf2db7e5ee28adb1acb4dbecb733edfdd29ecd7ebbd2df6fd18c8d2ba301afbba19d4ef06a952da7784f401bb69db3c1edb05e0de533a12ed7633f784c627633ceacb0e55543bc6eb9f3ba02d459e1e97f77946effbb1c9e2e87b906ca8172769fe6ecb0978a73f67ca8ebe61ebf3f1e8f39bb1e38d2cfd9f676cdd9612f15e7ec6ea8ebe61e7f563b1e73f622e00890b39d6172b654d49c2dcf8f44913ff7f8ff0dc763cef60247fa39bb4c7376f84bc5397b33d475738fff0f7b3ce6ec51e0483f673b3bf5b3c1b0978a73f64ea8ebe61ecfa71c8f397b2b7004c8d9dd3ace0e7ba93867ef87ba6eeef1dcdef198b3770147fa39db152867db3567a3f2b5ae28f2e71ecf331f8f39fb1070a49fb37b747e76f84bc539fb15a8ebe61e5ff3381e73f653b66cae333c61af33cc03ed49ab9d00daafad7622684f59ed24d07e03d70659fb2d5f3704ed77563b05b4a79d6baa467bc66aa782f67bab2d00ed59ab2d04ed39ab2d02ed0f565b0cdaf3566b04ed8f565b02da9facd604da9fadb614b4bf58ad19b4bf5aad05b4bf59ad15b4bf5bad08da3facd606da0b562b81f64fabb583f62fab7580f66fab2db39ab926c9d7be7e6cb571d0f7ee28bd1c8daf774583979cb3dd0de52561798a8568f07d40dcd6d2f4db6a377d6f8a86dff7a5c0d31ca0ef796863383ccdc0d3923e4ffc3db9d6f4f71b1fe326c7d33cb4d504fd2a06e8570edae27df336b757000dc78da287b12d7dc612deebc4fbe6ed3660640dc7311e87f9fc31ef31ff01de00e752fc3983dbe3efff32c752d0b9ced7eb07d8fecb6a75f0771cd35b1c2d505ec679c16df1be79bb1518b93f2da3cf581a2e63b3c3186a8cc8415bbc6fb76d3cdf978cbe67c33aae05d05e8631a934d231a90ed81a81b131908f49c75a4adb21deaf72d0068f6dec792be85ce7d9aaf2da8c6d1372036c01cebf52a59fdf703c483f8f4b453caf87c353049e10e77ea0f3b588effb2f46e9e65ac9f1aac5f1aa0075dac0bf5200ff86fa1cc2ed29b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb37c66bcff02af6f72bd46218cacb5024f8879fef8bbe4bc2fbb36d7751e80eb3ae95fb72815f19a25dfb7b7d0e97335d479343750f7615bf65d1bc46b9a8d61bd1bd67d1675d1b1d762435e434cba0eecbb7ed9905adba53da1aeb799e75c9867123439be367a3c0d709fca204f738ea7787fdc6287c7e4e9f355036c21aefd557a2d12bde2729ad7f6f01e83b0c7a53c7e702e544583c70f7c9f694fbdedc1d730f97a79bbd37635d4f9466ee0d8f03d90fc5b07ee3d4fa64e87b36f7ecd42d03b9c7dd7dbd732478db3ff26782dd7f9368ca9bb205743dcff81e372047dc5a51bca78dd3cfdf7e1f275fc62053c25e00931ce04fabc51c47320edebf81d8e57becf315ca71dfceb08e09fefb3286f737bcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9f19bf2bcaac79a8d72a847194ee7d88af67f0734778ffe6bace96aa8176435f87e36b4e8b9c3e57439dbbab06ea6eb3e5bae8d8fb1d928e6580eb79431e4b6eaf0efa83d782427d9fbbcde169f378c1e586d4da2e5fc74fdfe381ebf845c7d7568fa7a1ce57bcc68a9ee2f9dae2f0e0b5d1bae8d87b4bf2b09fd1b87728292fb83d3c97da40e3327e3f3ac471c6f712f7be1e6e0faf5f5f63bdad8f421dfb5231e4b8b10cfad41d1d9bdfd550e7308c7d476c19efe1c07b476ef5fc9d97a1ae53b37f819ee3161fdf15c0d90ded60db5dc09a52db6dd876ce06b7c37a35946fa91aa8eb3ea78cbd6676738eb8cf52f3bdaec5795d01ea2cf7f4bf3b4ab7ff9d0e4fa7c36c8ec9759067b7c2fb7fa831697982470bc123ae839f8342bd77baf757baf715e2385aebd4e1d756439ddb618c4aba7fd4f71e10fa7d8cf7ed7b1f73df1786739fe72bfd3eadfb60bc48fb3eadfb2087f03eadc8d9ff22d83f73d546c9ef2d5ce72167ffee67727e0dde07c6751e81f1e229f8ace37efec67ba646e3ff5749f749737bf8b986ff369cbe1be66550bf3b4566cc0964c1cf095ce793ce31eb48e05eea79eda309af65aff83954f8ff17d73fe343eacf90b5e77ca7d317ceebe5d017aef345e73360a8e77ca7dfd7c19f49781c68f3f495eb7c0dceb5c7e0331e1f27fc7fc7e39ebff332d467407ceeedcaf4fb1c1f5f7cbe6b37b4836daf06d694da6ec3b6f93320b7c37a35947f0a633ad7633fd86b6637e7087f8e4276f775edceeb0a50a7cbd3ffee28ddfeaf7478563acce6987c0bf2ec71f80c186aacee4af0681178c475f0bb41fc3e82cf90f5cd75bc5cff9fc6cf52383e3f15745ecdfffee7ceabf93e232c723cc6cf08cfc0389bf7d475e70bf9fd32cdfb86f1bb124dd0eef39e76bb53f6b3197ceb866dfc5cf072b61de0b9a5f17744f0b982cc804b379499a100afabca00e3980c30566780b126038cb519601c9b01c67119601c9f01c6ffffbd6fc18cf90c304ecc00635d06180b19609c9401c6fa0c304ece00e3940c304ecd00e3b40c304ecf00e38c0c30cecc00e3ac0c30cece00e39c0c30cecd00e3bc0c309e9001c61333c0785206181b32c0787206184fc900e37c654c85717158c6d248190d4fa8df27ace437f146e3f709977ada0a705da45469dff15a4988e7a755fa7b89cc50888efdfdaf408ca591321a9e96f4792afe7dcd16f0ccf73b9801185fd26f48497a6e1bde9fbe242c63e9a53c5b2ec4b31647fafc30bcc7604958c697f48cb310f71054fa8c33dfef6e2e09cb581a2963a87b42f0fe93e1f0f8ee13591296b13452c650df83c0ef6a0d87a71d3c2b793c0bc0581a2963a87ba62abda70fefed6ef77826891179d27ebe68bba7ad6502face0c59631c9f01c6091960cc678071620618eb32c058c800e3a40c30d6678071720618a76480716a0618a76580717a06186764807166061867658071760618e76480716e0618e7658051ff5fa88c2f3723f234a4c73368fe03db0af1bdd64afbbedcc393e2f73e07f51ddb0af08c938afb8ecf02c912e3b20c30067e9e8dfaa88ccaa88c7a5eab8fe219d547f5511995511995f195ce9885315c1933918fa591321a9e15813cebac80670578c6af5b1296b1345246c313e2d9b8796863383c5de0d90a8f6701184b2365343c019ee3177bd655010f3eefaecbe35900c6d248190dcfaa409eadac80671578b6d2e35900c6d248190d4f886716e6a18de1f0ac06cf56793c0bc0581a29a3e159933e4fecd9ea0a78d68067ab3d9e05602c8d94d1f0ac4d9f27f66c4d053c6bc1b3351ecf02309646ca6878d6a5cf137bb6b6029e75e0d95a8f6701184b23651c077a8a3cb167eb2ae0e906cfd6793c93cad89101c6651960cc828fcaa88c9218f5bc561f2531aa8feaa3322aa332669771790618f5582ba354c69ef4194b9532f6004f77fa3c6d81fa19fffed469765f293e13a164bc3addf16a9de35501ea9c06fe9d1ec0bf1cb4cbfbe66d6eaf52e6530530076abbc4bf8bbcce696f99e38759ceb0eb1ad0f137dc5f65cbfcdb735c1f7f878ceb6cb63ff4c1bf69c94b15f4f78cf4fbdb36d4b9cded214f8b309ea5c2787a84f1cc15c6335d18cf1a613c9384f1ac14c6335e18cf42613cf8bb5b12783a85f1cc13c6b34818cf0c613cf5c2782608e32909e3a916c6d32a8ca74918cf7c613c3385f1ac15c6335918cf62613c79613c2b84f1d408e359258c6781309e59c278a608e399288ca756184f51184fa3309e66613cb385f14c15c6b35a184f9d309e2e613c6385f1b40be399238c679a309e82309e71c278da84f1e404f0e4a363ef59c8c3df7b40ab725e6bc6abffad1ff8fb9956af82d79c65cb633cfb3e1334beb67b96e7b5e8d399d0976e5b2ebeb425f609dbea866d6eaf0e38ce12c2d3268c679c309e82309e69c278e608e36917c63356184f97309e3a613cab85f14c15c6335b184fb3309e46613c45613cb5c278260ae399228c6796309e05c2785609e3a911c6b342184f5e18cf62613c9385f1ac15c6335318cf7c613c4dc2785a85f1540be32909e399208ca75e18cf0c613c8b84f1cc13c6d3298c678c309e85c278c60be359298c6792309e35c278a60be3992b8ca74718cf52613c2dc278aa3c3c3d8178f8fa2def9bb77b84b41de038c4df8b3f3b509fd6db7dd5d8fd323fb7570d75eead2dafcde75d7c2d73b9d7dbf15c5e0f1ead0fd4173e1e39e7f8046ebb03ef2b88802172fc893c3c21eec708d4cf417998e2f3198ac6ab731cafdc6357803a67837fe704f0cf97dbbccded29b3322731e3ef32306b1eeab50b6164ed8ca03c1dc54a7f3be21ce009f15e11c8f7781cdbe0f4a9dde33bd7c15cdd10a09fbe7387b73778da6e88d2f562e330bcd8e8e1d938ca5e707b95329f9d4166f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466093e1b1efe8e34b3e6a15ea71046d6d687e589bf6fd4190d5e72ce7637943702cf3901fc09d4cff81ef24d4e9f3a3dbe731d3cbf3605e8a7efdce1ed4d701c2a61de904166f57964cc86879f75c5ac79a8b74208236be784e589c7b115d1e065a8716c13f08418e703f5331ec7363b7d5ae1f19debe0f9b539403f7de70e6f6f86e3a0cccaec63363cfc8c6066cd43bd2e218cac6d0cca538abfdfd8150d5e861ac736034f88713e90eff138b6c5e95397c777ae83b9ba25403f7de70e6f6f81e35009f3860c32abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3fafccaf1d9f0f0b3ce99350ff5560a61646d53509ef6f8bac3ca68f032d475872dc0b339759ef2758700bec7d71dce75fab4d2e33bd7c1f3ebdc00fdf49d3bbc7d2e1c87e39d7943069935374687597343999398353794398959734399939835379439895973439993983537943989597343999398353794398959734399939835379439895973439993983537943989597343999398353794398959426e189e55b6ccac79a8b74a08236b9bc3f2c4cf3d58150d5e86ba6fe75ce0d912c09f40fd8cefdb39cfe9d32a8fef5c07cfaff302f4d377eef0f679701c9459997dcc8667b52d336b1eeaad16c2c8da96b03cf138b63a1abc0c358e9d073c21c6f940fd8cc7b1ad4e9f567b7ce73a98ab5b03f4d377eef0f656380ecaaccc3e66c3b3c69699350ff5d6086164eddcb03cf138b6261abc0c358e6d059e10e37ca07ec6e3d836a74f6b3cbe731dccd56d01fae93b77787b1b1c076556661fb3e1596bcbcc9a877a6b8530b2869f7f98edc5f478961580a50ada0a3586474edf79c17ce1a54518cf52613c7385f14c17c6334918cf78613c0b85f18c11c6334f18cf22613c3384f1d40be399208ca7248ca75a184fab309e26613cf385f1cc14c6335918cf62613c79613c35c2781608e399258c678a309e89c2786a85f11485f1340ae36916c6d3238c67b6309ea9c278ea84f18c15c6334718cf34613c05613ce384f1b409e3c909e0c947c75ee7c4eb276340e3eb196b413bdf967b40abf2b4c1fbd9061acf17f03ecc783376f2b1ed5579dadbe6e11a0d3fb1ad6ed8e6f6ea80639b109e36613ce384f11484f14c13c6334718cf58613c75c278a60ae3992d8ca747184fb3309e46613c45613cb5c278260ae399228c6796309e05c2786a84f1e485f12c16c6335918cf4c613cf385f13409e36915c6532d8ca7248c6782309e7a613c3384f12c12c6334f18cf18613c0b85f18c17c6334918cf74613c7385f12c15c6d3228ca7cac37341fa3cf177ca7aa2c1cb50d7642e08ec4fa07e16cd7e2fb4fb4af1bb2cf177d52e72bcea71bc2a409d0bc1bf8b02f897837679dfbccded29b33227311b1e9eebc5eba55caf5908236b5bc3f2c4e363733478196a7cbc0878028c636d81fa198f63db9d3e357b7ce73a98abdb03f4d377eef0f6764fdb0d51ba5e5c3c0c2f2ef6f05c3cca5e707b95325f984166093e1b1efeeccaac79a8b75408236b1784e589c7c7a5d1e065a8f1f162e009f1fe11a89ff1987089d3a7a51edfb90e9e5f9704e8a7efdce1ed4be03854c2bc3d83cceaf3c8980d0fcff9336b1eeae1f7c05e4e46d62e0aca538a7fa3b2291abc0c358e5d023c21c6f940bec7e3d8a54e9f9a3cbe731d3cbf2e0dd04fdfb9c3db97c2715066655666655666655666655666655666655666655666655666655666655666d9cc8687bfbbc7ac79a8d7288491b58b83f294af3b34468397a1ae3b5c0a3c21aecb04f23dbeee7099d3a7468fef5c0773f5b200fdf49d3bbc7d191c076556666556666556666556666556666556666556666556666556666556666596cd6c785a6c9959f350af4508236b9784e589bfb7d5120d5e86baee7019f084b82e13a89ff17587cb9d3eb5787ce73a98ab9707e8a7efdce1edcbe13828b332fb980d0f3f1b8d59f350af5508236b9706e5295f3f6d8d062f438d6397034f88713e90eff138b6c3e953abc777ae83b9ba23403f7de70e6fef80e35009f3f60c32abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3fafccaf1d9f0f06f9c316b1eea158530b27659509ef6f8ba43311abc0c75dd6107f084b82e13c8f7f8bac3154e9f8a1edfb90e9e5f5704e8a7efdce1ed2be0381cefccdb33c8acb9313acc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc1272c3f0b4717b769d877a6d421859bb3c2c4ffcdc83b668f032d47d3b5700cf8e00fe04ea677cdfce4ea74f6d1edfb90e9e5f3b03f4d377eef0f64e380e3b9559993dcc86a764cbcc9a877a25218caced08cb138f63a568f032d438b61378428cf381fa198f63bb9c3e953cbe731dccd55d01fae93b77789bdb5366654e62366def4ebfed783cc0b6d99fc8e1e16577602f02f5331e0ff6447e8fb9bd02d4c163be27403f73d02eef9bb7f7c071a884797b0699d5e791319bb6f7a6df763c1e60dbec4fe4f0f0b237b01781fa198f07bd91df636eaf0075304f7b03f43307edf2be79bb178e4325ccdb33c8ac3e8f8cd9b4bd2ff5b6cbcf49c3b6d99fc8e1e1655f602fc2f4b33c1e5c19f93de6f60a5007f3f4ca00fdcc41bbbc6fdebe128e83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66366d5f957adbe5f97b6c9bfd891c1e5eae0aec45987e96e7eff7477e8fb9bd02d4c163be3f403f73d02eef9bb7f7c3715066655666655666655666655666655666655666655666655666655666655666d9cca6edabd36f3bfe3e0eb6cdfe440e0f2f5707f622503fe3f9fb6b22bfc7dc5e01eae031bf26403f73d02eef9bb7af81e3a0cccaec63366d1f48bdedf2f53c6c9bfd891c1e5e0e04f6224c3fcbe3c1c1c8ef31b757803a78cc0f06e8670edae57df3f641380e95306fcf20b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfaf1c9f4ddb87526fbb3d9ebfc7b6d99fc8e1e1e550602fc2f4b33c7fdf17f93de6f60a5007f3b42f403f73d02eef9bb7fbe0381cefccdb33c8acb9313acc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc1272c3b47d38fdb6e3efb363dbec4fe4f0f07238b01781fa19dfff726de4f798db2b401dccd36b03f43307edf2be79fb5a380ecaaccc3e663c4fc6a5d7767c3f1cb75165d7463b62cb63403b6acbd5a0f5db720d68d7d9722d68d7dbf258d06e80feb076a32d2f06ed265b2e81f66a5bbe02b4d7d8f24ed05e6bcbbb407b9d2def06ed665bde03daeb6d792f68b7d8722f68b7daf23ed0de60cb5782f6465bbe0ab437d9f27ed0de6ccb5783f6165bbe06b4b7daf201d06eb3e583a0dd6ecb87407b9b2df78176872dcf07ed4e8ff6765bbe10b47778b4bb6c793c6877dbf204d0de09655ebfcb962782f66e5bae03ed3db65c00edbdb63c09b4f7d9723d68f7d8f264d0eeb5e529a0dd67cb5341bbdf96a781f6802d4f07ed415b9e01da43b63c13b4f7dbf22cd01eb6e5d9a03d62cb7340fb802dcf05ed83b63c0fb40fd9321ea30fdbf261d0781cb816341e078e80c6e3c051d0781ce8078dc781eb40e371e07ad0781cb80134ce9d1b41e3dcb90934ce9d5783c6b9f31ad038775e0b1ae7ceeb40e3dcb91934ce9dd783c6b9730b689c3bb782c6b9f306d03877de081ae7ce9b40e3dc7933689c3b6f018d73e7ada071eedc061ae7ceeda071eebc0d34ce9d3b403bc196ef04ed445b7e3b6827d9f23b406bb0e5bb403bd996ef06ed145bc67181c79f778176aa2dbf1bb405b6fc1ed016daf27b415b64cbef038ddf73ee01add196ef056d892ddf075a932ddf0fda525b7e00b4665b7e10b4165b7e08b4565b7e3f68455b7e18b4365b7e04347e9ffc0068edb6fc41d03a6cf943a02db3651e17ccf967ce19ee33fb5107fd6bf270b3360eb8bba3743f33715bbc6fde2e0223fbdd3afa8ca5e132b6388c86a714c033cc215e86fabf1f33189e36f87b5a3c81fa19ffdfafdde953d1e95301ea9c0afd6c0fd0cf1cb4cbfbe6ed76683bc431472f6aec7e17385e54439d27ed9b9c590de523efc3e46faba72fcb03f785f7cde3d2f25168bbc369bbd9691bc75e5e863abf3a8079590066b3dfcef4f71b9f5f2becbe38a7b89d66e853177890569fb0ed9c0d6e87f56a28bf503f5097ebb11ffcfec5ec2697f95822bbfbba92f3ba02d459eee97f77946eff3b1d9e4e87d91c93e7ea0738029c0f710e2c773878bb19bceb4cf06e3978c775f0fdaf259077cb1c1ede6e011efe8cd30e1a7f56c03908fe7bd32870bbe35ebb879bb50e606cf13036a7cf187fd669711879bb1918595b063c1d813c738ff502c71f7c5fae75eaf06baba1ceffc07b63de53d79c77ff817ef1ff995f8cd21dd36b03f885ff9f8fc09fc8f13002bfb89f350178264403ffa73fdadf7764d795bd5b7b77edcd015ab58389eb9ca71b55a061798c478ba2c1531738e5c9531738e559e5d88253265cdffc57ca748ba7077a0feeefbfe050efa13d476e3adcdfbb7763df95485de3d02369520f9014355f8f86a21f1f1d7bf0533d33196e3eec3f6741c6d84ed4582063dfb868c03e9ed931efd66644313335e68c343331c65a33d3626656cc4c8a99393133256666c4cc8498990f33d3616636cc4c8699b93033150d517926e214e0f931309aff2198b3ddcc24989903335360de25cca74f33b29a4f12669433a39b7917339f92cdff98ccc861466533e29851c2bceb99773bf3e9c4bc5bafa45845b19a620dc55a8a75d6eb1e8ad3284ea73883e2551467529c457136c57a8a732836506ca4d844b199620bc5b914e7516ca5d846713ec5055179e6efa2a87c85f3628a4b282ea5b88ce2728a1d5179467d67549e313733e46646dccc809b196f33c36d66b4cd0cb699b13633d4d744e5196833e36c6698cd8cb2994d34b38766b6d0cc0e9ad94033fb6766fbccec9e99cd33b37766b6ceccce99d93833fb6666dbccecda2d5179f6cccc9699d931331b6666bfcc6c9799dd32b35966f6cacc56dd119567a3ccec93996d32b34b6636c9cc1e99d922333b646683ccec8f99ed31b33b6636c7ccde98d91a333b636663ccec8b996d31b32b8f44e5d913335b626647cc6cc847283e4af1318a8f537c82e293149fa2f834c5a3149fa1f82cc5e7283e4ff1058a2f527c89e2cb145fa1f82ac5d728be4ef118c53728be49f12d8a6f537c87e2bb14dfa3f83ec50f287e48f1a3a89c933fa1f829c5e3143fa3f839c52f287e49f12b8a27289ea4f835c55314bfa1f82dc5ef289ea67886e2f714cf523c47f1078ae729fe48f1278a3f53fc85e2af147fa3f83bc53f285ea0f827c5bf28fe1d0dcca4e240f198dde059bd5dfdfdbd070ff737f4f7351cbcee40fffec3076e6ab8617fff550d7dd7f71ed977a0ef067cf1d57618e229cb9e234776ddd4b0ffd0dede1b1bfaaeeb6fe8dbd7b0bbefba437b8fe28b6eb32f9a776c8bbbf6ee4d6eecdeaa9740fae0081bfd847d1d4f06af1fba6f9f1e89215f18c98b9e1e618736d97791d5767b5bf99dbae1e881befe8662c321fa77d7017a4defde9606fcdb5132f9687fc3d1fe5d47fa1bf61de93bd8d0d682fbbda776049d78a27e042ffaeffae1f73cfa3fac10a5ab91130300", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x25ff42e7b5351646829b6ce29c6a64660cbcc9d81954e67ab57d47dfbc096613", + "id": "0x0c57b7573675e1f7ee1d41a4e4ca808641ca7850826ca4966a4949230d821e85", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x2152b1029338584a8d43bbf80c6da9cf988c33c54e1f9b86741a2fa94986fe6b" + "publicBytecodeCommitment": "0x15886fadf17a38ace1697ec5b797f23e63ca8e75bc337ed1201cf43f0b52b146" }" `; diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts index 438ea71f76ff..326e410a257e 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts @@ -22,7 +22,6 @@ import { MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - NUM_FIELDS_PER_SHA256, } from '../../constants.gen.js'; import { CallRequest } from '../call_request.js'; import { PublicDataUpdateRequest } from '../public_data_update_request.js'; @@ -62,14 +61,14 @@ export class CombinedAccumulatedData { public newL2ToL1Msgs: Tuple, /** * Accumulated encrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public encryptedLogsHash: Tuple, + public encryptedLogsHash: Fr, /** * Accumulated unencrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public unencryptedLogsHash: Tuple, + public unencryptedLogsHash: Fr, /** * Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations */ @@ -118,8 +117,8 @@ export class CombinedAccumulatedData { reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + Fr.fromBuffer(reader), + Fr.fromBuffer(reader), Fr.fromBuffer(reader), Fr.fromBuffer(reader), reader.readArray(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest), @@ -143,8 +142,8 @@ export class CombinedAccumulatedData { makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + Fr.zero(), + Fr.zero(), Fr.zero(), Fr.zero(), makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), @@ -244,14 +243,14 @@ export class PublicAccumulatedRevertibleData { public newL2ToL1Msgs: Tuple, /** * Accumulated encrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public encryptedLogsHash: Tuple, + public encryptedLogsHash: Fr, /** * Accumulated unencrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public unencryptedLogsHash: Tuple, + public unencryptedLogsHash: Fr, /** * Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations */ @@ -295,8 +294,8 @@ export class PublicAccumulatedRevertibleData { this.privateCallStack.every(x => x.isEmpty()) && this.publicCallStack.every(x => x.isEmpty()) && this.newL2ToL1Msgs.every(x => x.isZero()) && - this.encryptedLogsHash.every(x => x.isZero()) && - this.unencryptedLogsHash.every(x => x.isZero()) && + this.encryptedLogsHash.isZero() && + this.unencryptedLogsHash.isZero() && this.encryptedLogPreimagesLength.isZero() && this.unencryptedLogPreimagesLength.isZero() && this.publicDataUpdateRequests.every(x => x.isEmpty()) @@ -311,8 +310,8 @@ export class PublicAccumulatedRevertibleData { privateCallStack: [${this.privateCallStack.map(h => h.toString()).join(', ')}], publicCallStack: [${this.publicCallStack.map(h => h.toString()).join(', ')}], newL2ToL1Msgs: [${this.newL2ToL1Msgs.map(h => h.toString()).join(', ')}], - encryptedLogsHash: [${this.encryptedLogsHash.map(h => h.toString()).join(', ')}], - unencryptedLogsHash: [${this.unencryptedLogsHash.map(h => h.toString()).join(', ')}], + encryptedLogsHash: ${this.encryptedLogsHash}, + unencryptedLogsHash: ${this.unencryptedLogsHash}, encryptedLogPreimagesLength: ${this.encryptedLogPreimagesLength} unencryptedLogPreimagesLength: ${this.unencryptedLogPreimagesLength} publicDataUpdateRequests: [${this.publicDataUpdateRequests.map(h => h.toString()).join(', ')}], @@ -332,8 +331,8 @@ export class PublicAccumulatedRevertibleData { reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + Fr.fromBuffer(reader), + Fr.fromBuffer(reader), Fr.fromBuffer(reader), Fr.fromBuffer(reader), reader.readArray(MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest), @@ -371,8 +370,8 @@ export class PublicAccumulatedRevertibleData { makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + Fr.zero(), + Fr.zero(), Fr.zero(), Fr.zero(), makeTuple(MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), @@ -409,14 +408,14 @@ export class PrivateAccumulatedRevertibleData { public newL2ToL1Msgs: Tuple, /** * Accumulated encrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public encryptedLogsHash: Tuple, + public encryptedLogsHash: Fr, /** * Accumulated unencrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public unencryptedLogsHash: Tuple, + public unencryptedLogsHash: Fr, /** * Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations */ @@ -458,8 +457,8 @@ export class PrivateAccumulatedRevertibleData { reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + Fr.fromBuffer(reader), + Fr.fromBuffer(reader), Fr.fromBuffer(reader), Fr.fromBuffer(reader), ); @@ -481,8 +480,8 @@ export class PrivateAccumulatedRevertibleData { makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + Fr.zero(), + Fr.zero(), Fr.zero(), Fr.zero(), ); diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index af79b7382ba4..19b9ebd8985c 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -15,7 +15,6 @@ import { MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - NUM_FIELDS_PER_SHA256, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, RETURN_VALUES_LENGTH, } from '../constants.gen.js'; @@ -93,14 +92,14 @@ export class PrivateCircuitPublicInputs { public endSideEffectCounter: Fr, /** * Hash of the encrypted logs emitted in this function call. - * Note: Represented as an array of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public encryptedLogsHash: Tuple, + public encryptedLogsHash: Fr, /** * Hash of the unencrypted logs emitted in this function call. - * Note: Represented as an array of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public unencryptedLogsHash: Tuple, + public unencryptedLogsHash: Fr, /** * Length of the encrypted log preimages emitted in this function call. * Note: Here so that the gas cost of this request can be measured by circuits, without actually needing to feed @@ -160,8 +159,8 @@ export class PrivateCircuitPublicInputs { reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), reader.readObject(Fr), reader.readObject(Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + reader.readObject(Fr), + reader.readObject(Fr), reader.readObject(Fr), reader.readObject(Fr), reader.readObject(Header), @@ -187,8 +186,8 @@ export class PrivateCircuitPublicInputs { reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), reader.readField(), reader.readField(), - reader.readFieldArray(NUM_FIELDS_PER_SHA256), - reader.readFieldArray(NUM_FIELDS_PER_SHA256), + reader.readField(), + reader.readField(), reader.readField(), reader.readField(), reader.readObject(Header), @@ -217,8 +216,8 @@ export class PrivateCircuitPublicInputs { makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message.empty), Fr.ZERO, Fr.ZERO, - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + Fr.ZERO, + Fr.ZERO, Fr.ZERO, Fr.ZERO, Header.empty(), @@ -245,8 +244,8 @@ export class PrivateCircuitPublicInputs { isZeroArray(this.privateCallStackHashes) && isZeroArray(this.publicCallStackHashes) && isEmptyArray(this.newL2ToL1Msgs) && - isZeroArray(this.encryptedLogsHash) && - isZeroArray(this.unencryptedLogsHash) && + this.encryptedLogsHash.isZero() && + this.unencryptedLogsHash.isZero() && this.encryptedLogPreimagesLength.isZero() && this.unencryptedLogPreimagesLength.isZero() && this.historicalHeader.isEmpty() && diff --git a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts index df9f69807f28..f9b3488558e2 100644 --- a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts @@ -16,7 +16,6 @@ import { MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH, RETURN_VALUES_LENGTH, } from '../constants.gen.js'; @@ -94,9 +93,9 @@ export class PublicCircuitPublicInputs { public endSideEffectCounter: Fr, /** * Hash of the unencrypted logs emitted in this function call. - * Note: Represented as an array of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public unencryptedLogsHash: Tuple, + public unencryptedLogsHash: Fr, /** * Length of the unencrypted log preimages emitted in this function call. */ @@ -145,7 +144,7 @@ export class PublicCircuitPublicInputs { makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message.empty), Fr.ZERO, Fr.ZERO, - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + Fr.ZERO, Fr.ZERO, Header.empty(), AztecAddress.ZERO, @@ -172,7 +171,7 @@ export class PublicCircuitPublicInputs { isArrayEmpty(this.newL2ToL1Msgs, item => item.isEmpty()) && this.startSideEffectCounter.isZero() && this.endSideEffectCounter.isZero() && - isFrArrayEmpty(this.unencryptedLogsHash) && + this.unencryptedLogsHash.isZero() && this.unencryptedLogPreimagesLength.isZero() && this.historicalHeader.isEmpty() && this.proverAddress.isZero() && @@ -247,7 +246,7 @@ export class PublicCircuitPublicInputs { reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), reader.readObject(Fr), reader.readObject(Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + reader.readObject(Fr), reader.readObject(Fr), reader.readObject(Header), reader.readObject(AztecAddress), @@ -272,7 +271,7 @@ export class PublicCircuitPublicInputs { reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), reader.readField(), reader.readField(), - reader.readFieldArray(NUM_FIELDS_PER_SHA256), + reader.readField(), reader.readField(), Header.fromFields(reader), AztecAddress.fromFields(reader), diff --git a/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts b/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts index d44621ca084f..87658904f2e8 100644 --- a/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts @@ -1,7 +1,6 @@ import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { NUM_FIELDS_PER_SHA256 } from '../../constants.gen.js'; import { AggregationObject } from '../aggregation_object.js'; import { PartialStateReference } from '../partial_state_reference.js'; import { RollupTypes } from '../shared.js'; @@ -39,15 +38,15 @@ export class BaseOrMergeRollupPublicInputs { */ public end: PartialStateReference, /** - * SHA256 hashes of transactions effects. Used to make public inputs constant-sized (to then be unpacked on-chain). - * Note: Length 2 for high and low. + * SHA256 hash of transactions effects. Used to make public inputs constant-sized (to then be unpacked on-chain). + * Note: Truncated to 31 bytes to fit in Fr. */ - public txsEffectsHash: Tuple, + public txsEffectsHash: Fr, /** - * SHA256 hashes of outhash. Used to make public inputs constant-sized (to then be unpacked on-chain). - * Note: Length 2 for high and low. + * SHA256 hash of outhash. Used to make public inputs constant-sized (to then be unpacked on-chain). + * Note: Truncated to 31 bytes to fit in Fr. */ - public outHash: Tuple, + public outHash: Fr, ) {} /** @@ -65,8 +64,9 @@ export class BaseOrMergeRollupPublicInputs { reader.readObject(ConstantRollupData), reader.readObject(PartialStateReference), reader.readObject(PartialStateReference), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr) as [Fr], - reader.readArray(NUM_FIELDS_PER_SHA256, Fr) as [Fr], + //TODO check + Fr.fromBuffer(reader), + Fr.fromBuffer(reader), ); } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 056fc3d51336..b3fa568ed3f9 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -71,7 +71,6 @@ import { NULLIFIER_TREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NUM_BASE_PARITY_PER_ROOT_PARITY, - NUM_FIELDS_PER_SHA256, NUM_MSGS_PER_BASE_PARITY, NoteHashReadRequestMembershipWitness, NullifierKeyValidationRequest, @@ -289,8 +288,8 @@ export function makeCombinedAccumulatedData(seed = 1, full = false): CombinedAcc tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), tupleGenerator(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x500), tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x600), - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x800), // unencrypted logs hash + fr(seed + 0x700), // encrypted logs hash + fr(seed + 0x800), // unencrypted logs hash fr(seed + 0x900), // encrypted_log_preimages_length fr(seed + 0xa00), // unencrypted_log_preimages_length tupleGenerator(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makePublicDataUpdateRequest, seed + 0xd00), @@ -311,8 +310,8 @@ export function makeCombinedAccumulatedRevertibleData(seed = 1, full = false): P tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), tupleGenerator(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x500), tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x600), - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x800), // unencrypted logs hash + fr(seed + 0x700), // encrypted logs hash + fr(seed + 0x800), // unencrypted logs hash fr(seed + 0x900), // encrypted_log_preimages_length fr(seed + 0xa00), // unencrypted_log_preimages_length tupleGenerator(MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makePublicDataUpdateRequest, seed + 0xd00), @@ -333,8 +332,8 @@ export function makeFinalAccumulatedData(seed = 1, full = false): PrivateAccumul tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), tupleGenerator(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x500), tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x600), - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x800), // unencrypted logs hash + fr(seed + 0x700), // encrypted logs hash + fr(seed + 0x800), // unencrypted logs hash fr(seed + 0x900), // encrypted_log_preimages_length fr(seed + 0xa00), // unencrypted_log_preimages_length ); @@ -427,7 +426,7 @@ export function makePublicCircuitPublicInputs( tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, makeL2ToL1Message, seed + 0x900), fr(seed + 0xa00), fr(seed + 0xa01), - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x901), + fr(seed + 0x901), fr(seed + 0x902), makeHeader(seed + 0xa00, undefined), makeAztecAddress(seed + 0xb01), @@ -873,8 +872,8 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn newL2ToL1Msgs: makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, makeL2ToL1Message, seed + 0x800), startSideEffectCounter: fr(seed + 0x849), endSideEffectCounter: fr(seed + 0x850), - encryptedLogsHash: makeTuple(NUM_FIELDS_PER_SHA256, fr, seed + 0x900), - unencryptedLogsHash: makeTuple(NUM_FIELDS_PER_SHA256, fr, seed + 0xa00), + encryptedLogsHash: fr(seed + 0x900), + unencryptedLogsHash: fr(seed + 0xa00), encryptedLogPreimagesLength: fr(seed + 0xb00), unencryptedLogPreimagesLength: fr(seed + 0xc00), historicalHeader: makeHeader(seed + 0xd00, undefined), @@ -994,8 +993,8 @@ export function makeBaseOrMergeRollupPublicInputs( makeConstantBaseRollupData(seed + 0x200, globalVariables), makePartialStateReference(seed + 0x300), makePartialStateReference(seed + 0x400), - [fr(seed + 0x901)], - [fr(seed + 0x902)], + fr(seed + 0x901), + fr(seed + 0x902), ); } diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index d6a568def0ba..9ac6843c533b 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -24,7 +24,6 @@ import { import { fr, makeNewSideEffect, makeNewSideEffectLinkedToNoteHash, makeProof } from '@aztec/circuits.js/testing'; import { L1ContractAddresses, createEthereumChain } from '@aztec/ethereum'; import { makeTuple, range } from '@aztec/foundation/array'; -import { toTruncField } from '@aztec/foundation/serialize'; import { openTmpStore } from '@aztec/kv-store/utils'; import { AvailabilityOracleAbi, InboxAbi, OutboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; @@ -181,8 +180,8 @@ describe('L1Publisher integration', () => { processedTx.data.end.newNullifiers[processedTx.data.end.newNullifiers.length - 1] = SideEffectLinkedToNoteHash.empty(); processedTx.data.end.newL2ToL1Msgs = makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x300); - processedTx.data.end.encryptedLogsHash = toTruncField(processedTx.encryptedLogs.hash()); - processedTx.data.end.unencryptedLogsHash = toTruncField(processedTx.unencryptedLogs.hash()); + processedTx.data.end.encryptedLogsHash = Fr.fromBuffer(processedTx.encryptedLogs.hash()); + processedTx.data.end.unencryptedLogsHash = Fr.fromBuffer(processedTx.unencryptedLogs.hash()); return processedTx; }; diff --git a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap index f9463a7ba89e..a1c940845b49 100644 --- a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap +++ b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap @@ -82,9 +82,7 @@ PrivateKernelInnerCircuitPublicInputs { }, "end": CombinedAccumulatedData { "encryptedLogPreimagesLength": Fr<0x000000000000000000000000000000000000000000000000000000000000000c>, - "encryptedLogsHash": [ - Fr<0x00f33ae280239814c4dfaaafc16fc138a8d3eae52bb962af6576cbb61c2af246>, - ], + "encryptedLogsHash": Fr<0x00f33ae280239814c4dfaaafc16fc138a8d3eae52bb962af6576cbb61c2af246>, "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -999,9 +997,7 @@ PrivateKernelInnerCircuitPublicInputs { "code": 0, }, "unencryptedLogPreimagesLength": Fr<0x000000000000000000000000000000000000000000000000000000000000000c>, - "unencryptedLogsHash": [ - Fr<0x00f33ae280239814c4dfaaafc16fc138a8d3eae52bb962af6576cbb61c2af246>, - ], + "unencryptedLogsHash": Fr<0x00f33ae280239814c4dfaaafc16fc138a8d3eae52bb962af6576cbb61c2af246>, }, "isPrivate": true, "minRevertibleSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, @@ -1890,9 +1886,7 @@ PrivateKernelTailCircuitPublicInputs { }, "end": PrivateAccumulatedRevertibleData { "encryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000138>, - "encryptedLogsHash": [ - Fr<0x000a6f11d0fee649628137ebedf70c9cf2e7b081a9e284c9608fc5741fa8fc7a>, - ], + "encryptedLogsHash": Fr<0x000a6f11d0fee649628137ebedf70c9cf2e7b081a9e284c9608fc5741fa8fc7a>, "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2540,9 +2534,7 @@ PrivateKernelTailCircuitPublicInputs { }, ], "unencryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000004>, - "unencryptedLogsHash": [ - Fr<0x006003947a07e21c81ce2062539d6d6864fe999b58b03fc46f6c190d9eac9b39>, - ], + "unencryptedLogsHash": Fr<0x006003947a07e21c81ce2062539d6d6864fe999b58b03fc46f6c190d9eac9b39>, }, "endNonRevertibleData": PrivateAccumulatedNonRevertibleData { "newNoteHashes": [ diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index daac082af2b6..443a294102b4 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -48,7 +48,6 @@ import { MergeRollupInputs, NULLIFIER_TREE_HEIGHT, NUM_BYTES_PER_SHA256, - NUM_FIELDS_PER_SHA256, NonMembershipHint, NoteHashReadRequestMembershipWitness, NullifierKeyValidationRequest, @@ -195,7 +194,6 @@ import { ConstantRollupData as ConstantRollupDataNoir, ContentCommitment as ContentCommitmentNoir, Field, - FixedLengthArray, GlobalVariables as GlobalVariablesNoir, Header as HeaderNoir, ParityPublicInputs as ParityPublicInputsNoir, @@ -696,8 +694,8 @@ export function mapPrivateCircuitPublicInputsToNoir( new_l2_to_l1_msgs: mapTuple(privateCircuitPublicInputs.newL2ToL1Msgs, mapL2ToL1MessageToNoir), start_side_effect_counter: mapFieldToNoir(privateCircuitPublicInputs.startSideEffectCounter), end_side_effect_counter: mapFieldToNoir(privateCircuitPublicInputs.endSideEffectCounter), - encrypted_logs_hash: mapTuple(privateCircuitPublicInputs.encryptedLogsHash, mapFieldToNoir), - unencrypted_logs_hash: mapTuple(privateCircuitPublicInputs.unencryptedLogsHash, mapFieldToNoir), + encrypted_logs_hash: mapFieldToNoir(privateCircuitPublicInputs.encryptedLogsHash), + unencrypted_logs_hash: mapFieldToNoir(privateCircuitPublicInputs.unencryptedLogsHash), encrypted_log_preimages_length: mapFieldToNoir(privateCircuitPublicInputs.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(privateCircuitPublicInputs.unencryptedLogPreimagesLength), historical_header: mapHeaderToNoir(privateCircuitPublicInputs.historicalHeader), @@ -810,8 +808,8 @@ export function mapTupleFromNoir( * @param hash - The hash as it is represented in Noir (1 fields). * @returns The hash represented as a 31 bytes long buffer. */ -export function mapSha256HashFromNoir(hash: FixedLengthArray): Buffer { - return Buffer.concat(hash.map(mapFieldFromNoir).map(fr => toBufferBE(fr.toBigInt(), NUM_BYTES_PER_SHA256))); +export function mapSha256HashFromNoir(hash: Field): Buffer { + return toBufferBE(mapFieldFromNoir(hash).toBigInt(), NUM_BYTES_PER_SHA256); } /** @@ -819,8 +817,8 @@ export function mapSha256HashFromNoir(hash: FixedLengthArray { - return toTruncField(hash).map(mapFieldToNoir) as FixedLengthArray; +export function mapSha256HashToNoir(hash: Buffer): Field { + return mapFieldToNoir(toTruncField(hash)[0]); } /** @@ -985,8 +983,8 @@ export function mapCombinedAccumulatedDataFromNoir( mapCallRequestFromNoir, ), mapTupleFromNoir(combinedAccumulatedData.new_l2_to_l1_msgs, MAX_NEW_L2_TO_L1_MSGS_PER_TX, mapFieldFromNoir), - mapTupleFromNoir(combinedAccumulatedData.encrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), - mapTupleFromNoir(combinedAccumulatedData.unencrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), + mapFieldFromNoir(combinedAccumulatedData.encrypted_logs_hash), + mapFieldFromNoir(combinedAccumulatedData.unencrypted_logs_hash), mapFieldFromNoir(combinedAccumulatedData.encrypted_log_preimages_length), mapFieldFromNoir(combinedAccumulatedData.unencrypted_log_preimages_length), mapTupleFromNoir( @@ -1023,8 +1021,8 @@ export function mapFinalAccumulatedDataFromNoir( mapCallRequestFromNoir, ), mapTupleFromNoir(finalAccumulatedData.new_l2_to_l1_msgs, MAX_NEW_L2_TO_L1_MSGS_PER_TX, mapFieldFromNoir), - mapTupleFromNoir(finalAccumulatedData.encrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), - mapTupleFromNoir(finalAccumulatedData.unencrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), + mapFieldFromNoir(finalAccumulatedData.encrypted_logs_hash), + mapFieldFromNoir(finalAccumulatedData.unencrypted_logs_hash), mapFieldFromNoir(finalAccumulatedData.encrypted_log_preimages_length), mapFieldFromNoir(finalAccumulatedData.unencrypted_log_preimages_length), ); @@ -1079,8 +1077,8 @@ export function mapPrivateAccumulatedRevertibleDataToNoir( private_call_stack: mapTuple(data.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(data.publicCallStack, mapCallRequestToNoir), new_l2_to_l1_msgs: mapTuple(data.newL2ToL1Msgs, mapFieldToNoir), - encrypted_logs_hash: mapTuple(data.encryptedLogsHash, mapFieldToNoir), - unencrypted_logs_hash: mapTuple(data.unencryptedLogsHash, mapFieldToNoir), + encrypted_logs_hash: mapFieldToNoir(data.encryptedLogsHash), + unencrypted_logs_hash: mapFieldToNoir(data.unencryptedLogsHash), encrypted_log_preimages_length: mapFieldToNoir(data.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(data.unencryptedLogPreimagesLength), }; @@ -1101,8 +1099,8 @@ export function mapCombinedAccumulatedDataToNoir( private_call_stack: mapTuple(combinedAccumulatedData.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(combinedAccumulatedData.publicCallStack, mapCallRequestToNoir), new_l2_to_l1_msgs: mapTuple(combinedAccumulatedData.newL2ToL1Msgs, mapFieldToNoir), - encrypted_logs_hash: mapTuple(combinedAccumulatedData.encryptedLogsHash, mapFieldToNoir), - unencrypted_logs_hash: mapTuple(combinedAccumulatedData.unencryptedLogsHash, mapFieldToNoir), + encrypted_logs_hash: mapFieldToNoir(combinedAccumulatedData.encryptedLogsHash), + unencrypted_logs_hash: mapFieldToNoir(combinedAccumulatedData.unencryptedLogsHash), encrypted_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.unencryptedLogPreimagesLength), public_data_update_requests: mapTuple( @@ -1184,8 +1182,8 @@ export function mapPublicAccumulatedRevertibleDataToNoir( private_call_stack: mapTuple(data.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(data.publicCallStack, mapCallRequestToNoir), new_l2_to_l1_msgs: mapTuple(data.newL2ToL1Msgs, mapFieldToNoir), - encrypted_logs_hash: mapTuple(data.encryptedLogsHash, mapFieldToNoir), - unencrypted_logs_hash: mapTuple(data.unencryptedLogsHash, mapFieldToNoir), + encrypted_logs_hash: mapFieldToNoir(data.encryptedLogsHash), + unencrypted_logs_hash: mapFieldToNoir(data.unencryptedLogsHash), encrypted_log_preimages_length: mapFieldToNoir(data.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(data.unencryptedLogPreimagesLength), public_data_update_requests: mapTuple(data.publicDataUpdateRequests, mapPublicDataUpdateRequestToNoir), @@ -1286,8 +1284,8 @@ export function mapFinalAccumulatedDataToNoir( private_call_stack: mapTuple(finalAccumulatedData.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(finalAccumulatedData.publicCallStack, mapCallRequestToNoir), new_l2_to_l1_msgs: mapTuple(finalAccumulatedData.newL2ToL1Msgs, mapFieldToNoir), - encrypted_logs_hash: mapTuple(finalAccumulatedData.encryptedLogsHash, mapFieldToNoir), - unencrypted_logs_hash: mapTuple(finalAccumulatedData.unencryptedLogsHash, mapFieldToNoir), + encrypted_logs_hash: mapFieldToNoir(finalAccumulatedData.encryptedLogsHash), + unencrypted_logs_hash: mapFieldToNoir(finalAccumulatedData.unencryptedLogsHash), encrypted_log_preimages_length: mapFieldToNoir(finalAccumulatedData.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(finalAccumulatedData.unencryptedLogPreimagesLength), }; @@ -1421,8 +1419,8 @@ export function mapPublicAccumulatedRevertibleDataFromNoir( mapTupleFromNoir(data.private_call_stack, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, mapCallRequestFromNoir), mapTupleFromNoir(data.public_call_stack, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, mapCallRequestFromNoir), mapTupleFromNoir(data.new_l2_to_l1_msgs, MAX_NEW_L2_TO_L1_MSGS_PER_TX, mapFieldFromNoir), - mapTupleFromNoir(data.encrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), - mapTupleFromNoir(data.unencrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), + mapFieldFromNoir(data.encrypted_logs_hash), + mapFieldFromNoir(data.unencrypted_logs_hash), mapFieldFromNoir(data.encrypted_log_preimages_length), mapFieldFromNoir(data.unencrypted_log_preimages_length), mapTupleFromNoir( @@ -1530,7 +1528,7 @@ export function mapPublicCircuitPublicInputsToNoir( new_l2_to_l1_msgs: mapTuple(publicInputs.newL2ToL1Msgs, mapL2ToL1MessageToNoir), start_side_effect_counter: mapFieldToNoir(publicInputs.startSideEffectCounter), end_side_effect_counter: mapFieldToNoir(publicInputs.endSideEffectCounter), - unencrypted_logs_hash: mapTuple(publicInputs.unencryptedLogsHash, mapFieldToNoir), + unencrypted_logs_hash: mapFieldToNoir(publicInputs.unencryptedLogsHash), unencrypted_log_preimages_length: mapFieldToNoir(publicInputs.unencryptedLogPreimagesLength), historical_header: mapHeaderToNoir(publicInputs.historicalHeader), @@ -1569,8 +1567,8 @@ export function mapBaseOrMergeRollupPublicInputsToNoir( constants: mapConstantRollupDataToNoir(baseOrMergeRollupPublicInputs.constants), start: mapPartialStateReferenceToNoir(baseOrMergeRollupPublicInputs.start), end: mapPartialStateReferenceToNoir(baseOrMergeRollupPublicInputs.end), - txs_effects_hash: mapTuple(baseOrMergeRollupPublicInputs.txsEffectsHash, mapFieldToNoir), - out_hash: mapTuple(baseOrMergeRollupPublicInputs.outHash, mapFieldToNoir), + txs_effects_hash: mapFieldToNoir(baseOrMergeRollupPublicInputs.txsEffectsHash), + out_hash: mapFieldToNoir(baseOrMergeRollupPublicInputs.outHash), }; } @@ -1617,8 +1615,8 @@ export function mapBaseOrMergeRollupPublicInputsFromNoir( mapConstantRollupDataFromNoir(baseOrMergeRollupPublicInputs.constants), mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.start), mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.end), - mapTupleFromNoir(baseOrMergeRollupPublicInputs.txs_effects_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), - mapTupleFromNoir(baseOrMergeRollupPublicInputs.out_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), + mapFieldFromNoir(baseOrMergeRollupPublicInputs.txs_effects_hash), + mapFieldFromNoir(baseOrMergeRollupPublicInputs.out_hash), ); } diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.test.ts index 73a2bd9fe2d3..8d11730cb788 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.test.ts @@ -45,7 +45,6 @@ import { } from '@aztec/circuits.js/testing'; import { makeTuple, range } from '@aztec/foundation/array'; import { padArrayEnd, times } from '@aztec/foundation/collection'; -import { toTruncField } from '@aztec/foundation/serialize'; import { sleep } from '@aztec/foundation/sleep'; import { openTmpStore } from '@aztec/kv-store/utils'; import { WASMSimulator } from '@aztec/simulator'; @@ -365,8 +364,8 @@ describe('prover/tx-prover', () => { processedTx.data.end.newNullifiers[tx.data.end.newNullifiers.length - 1] = SideEffectLinkedToNoteHash.empty(); processedTx.data.end.newL2ToL1Msgs = makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x300); - processedTx.data.end.encryptedLogsHash = toTruncField(processedTx.encryptedLogs.hash()); - processedTx.data.end.unencryptedLogsHash = toTruncField(processedTx.unencryptedLogs.hash()); + processedTx.data.end.encryptedLogsHash = Fr.fromBuffer(processedTx.encryptedLogs.hash()); + processedTx.data.end.unencryptedLogsHash = Fr.fromBuffer(processedTx.unencryptedLogs.hash()); return processedTx; }; diff --git a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts index 0ecd9e56caee..46474f870ae0 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -44,7 +44,7 @@ import { import { computeVarArgsHash } from '@aztec/circuits.js/hash'; import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; -import { Tuple, toTruncField } from '@aztec/foundation/serialize'; +import { Tuple } from '@aztec/foundation/serialize'; import { PublicExecution, PublicExecutionResult, @@ -348,7 +348,7 @@ export abstract class AbstractPhaseManager { ); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) --> set this in Noir - const unencryptedLogsHash = toTruncField(result.unencryptedLogs.hash()); + const unencryptedLogsHash = Fr.fromBuffer(result.unencryptedLogs.hash()); const unencryptedLogPreimagesLength = new Fr(result.unencryptedLogs.getSerializedLength()); return PublicCircuitPublicInputs.from({ diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index 802a7d98ff0f..1b88e0fb08c1 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -99,7 +99,7 @@ describe('public_processor', () => { const includeLogs = false; const tx = mockTx(seed, includeLogs); tx.data.end.publicCallStack = makeTuple(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty); - tx.data.end.unencryptedLogsHash = [Fr.ZERO]; + tx.data.end.unencryptedLogsHash = Fr.ZERO; tx.data.endNonRevertibleData.publicCallStack = makeTuple( MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty, @@ -203,7 +203,7 @@ describe('public_processor', () => { MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty, ); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; const tx = new Tx(kernelOutput, proof, TxL2Logs.empty(), TxL2Logs.empty(), publicCallRequests); @@ -246,7 +246,7 @@ describe('public_processor', () => { MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty, ); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; kernelOutput.needsSetup = false; kernelOutput.needsTeardown = false; @@ -290,7 +290,7 @@ describe('public_processor', () => { callRequests[2].callContext.sideEffectCounter = 4; const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; addKernelPublicCallStack(kernelOutput, { setupCalls: [callRequests[0]], @@ -406,7 +406,7 @@ describe('public_processor', () => { callRequests[2].callContext.sideEffectCounter = 4; const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; addKernelPublicCallStack(kernelOutput, { setupCalls: [callRequests[0]], @@ -510,7 +510,7 @@ describe('public_processor', () => { callRequests[2].callContext.sideEffectCounter = 4; const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; addKernelPublicCallStack(kernelOutput, { setupCalls: [callRequests[0]], @@ -614,7 +614,7 @@ describe('public_processor', () => { const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; addKernelPublicCallStack(kernelOutput, { setupCalls: [callRequests[0]], appLogicCalls: [callRequests[2]], diff --git a/yarn-project/simulator/src/client/private_execution.ts b/yarn-project/simulator/src/client/private_execution.ts index 1491b7d7dcb5..da23ae8daa83 100644 --- a/yarn-project/simulator/src/client/private_execution.ts +++ b/yarn-project/simulator/src/client/private_execution.ts @@ -47,9 +47,9 @@ export async function executePrivateFunction( const encryptedLogs = context.getEncryptedLogs(); const unencryptedLogs = context.getUnencryptedLogs(); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) --> set this in Noir - publicInputs.encryptedLogsHash = toTruncField(encryptedLogs.hash()); + publicInputs.encryptedLogsHash = toTruncField(encryptedLogs.hash())[0]; publicInputs.encryptedLogPreimagesLength = new Fr(encryptedLogs.getSerializedLength()); - publicInputs.unencryptedLogsHash = toTruncField(unencryptedLogs.hash()); + publicInputs.unencryptedLogsHash = toTruncField(unencryptedLogs.hash())[0]; publicInputs.unencryptedLogPreimagesLength = new Fr(unencryptedLogs.getSerializedLength()); const callStackItem = new PrivateCallStackItem(contractAddress, functionData, publicInputs); From bce69142d9a75ef12a35b8d1811979ca96dc40f1 Mon Sep 17 00:00:00 2001 From: MirandaWood Date: Fri, 22 Mar 2024 14:45:09 +0000 Subject: [PATCH 09/13] feat: add shaToField, clean up truncation --- yarn-project/circuit-types/src/l2_block.ts | 6 +- .../src/messaging/l1_to_l2_message.ts | 6 +- .../circuit-types/src/tx/processed_tx.ts | 4 +- .../src/structs/content_commitment.ts | 6 +- .../src/e2e_cross_chain_messaging.test.ts | 32 +- .../end-to-end/src/e2e_outbox.test.ts | 24 +- .../e2e_public_cross_chain_messaging.test.ts | 52 +-- .../src/shared/cross_chain_test_harness.ts | 41 +- .../end-to-end/src/shared/uniswap_l1_l2.ts | 407 ++++++++---------- .../foundation/src/crypto/sha256/index.ts | 7 + .../src/serialize/free_funcs.test.ts | 2 +- .../foundation/src/serialize/free_funcs.ts | 8 +- .../src/type_conversion.ts | 2 +- .../simulator/src/client/private_execution.ts | 5 +- yarn-project/simulator/src/test/utils.ts | 5 +- 15 files changed, 282 insertions(+), 325 deletions(-) diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index e02ea43329b8..db167a6640e7 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -1,8 +1,8 @@ import { Body, TxEffect, TxHash } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, Header, STRING_ENCODING } from '@aztec/circuits.js'; -import { sha256 } from '@aztec/foundation/crypto'; +import { sha256, sha256ToField } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer, toTruncField } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { makeAppendOnlyTreeSnapshot, makeHeader } from './l2_block_code_to_purge.js'; @@ -160,7 +160,7 @@ export class L2Block { this.body.getTxsEffectsHash(), ); - return toTruncField(sha256(buf))[0]; + return sha256ToField(buf); } /** diff --git a/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts b/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts index 248162c52ce1..5e94c56af01c 100644 --- a/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts +++ b/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts @@ -1,6 +1,6 @@ -import { sha256 } from '@aztec/foundation/crypto'; +import { sha256ToField } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer, toTruncField } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { L1Actor } from './l1_actor.js'; import { L2Actor } from './l2_actor.js'; @@ -45,7 +45,7 @@ export class L1ToL2Message { } hash(): Fr { - return toTruncField(sha256(serializeToBuffer(...this.toFields())))[0]; + return sha256ToField(serializeToBuffer(...this.toFields())); } static fromBuffer(buffer: Buffer | BufferReader): L1ToL2Message { diff --git a/yarn-project/circuit-types/src/tx/processed_tx.ts b/yarn-project/circuit-types/src/tx/processed_tx.ts index 50db53e96a77..d63dcd56e6ff 100644 --- a/yarn-project/circuit-types/src/tx/processed_tx.ts +++ b/yarn-project/circuit-types/src/tx/processed_tx.ts @@ -14,7 +14,7 @@ import { ValidationRequests, makeEmptyProof, } from '@aztec/circuits.js'; -import { Tuple, toTruncField } from '@aztec/foundation/serialize'; +import { Tuple } from '@aztec/foundation/serialize'; /** * Represents a tx that has been processed by the sequencer public processor, @@ -193,7 +193,7 @@ export function toTxEffect(tx: ProcessedTx): TxEffect { function validateProcessedTxLogs(tx: ProcessedTx): void { const unencryptedLogs = tx.unencryptedLogs || new TxL2Logs([]); const kernelUnencryptedLogsHash = tx.data.combinedData.unencryptedLogsHash; - const referenceHash = toTruncField(unencryptedLogs.hash())[0]; + const referenceHash = Fr.fromBuffer(unencryptedLogs.hash()); if (!referenceHash.equals(kernelUnencryptedLogsHash)) { throw new Error( `Unencrypted logs hash mismatch. Expected ${referenceHash.toString()}, got ${kernelUnencryptedLogsHash.toString()}. diff --git a/yarn-project/circuits.js/src/structs/content_commitment.ts b/yarn-project/circuits.js/src/structs/content_commitment.ts index 8b047bf2365a..b2f5ac0ae92b 100644 --- a/yarn-project/circuits.js/src/structs/content_commitment.ts +++ b/yarn-project/circuits.js/src/structs/content_commitment.ts @@ -31,9 +31,9 @@ export class ContentCommitment { toFields(): Fr[] { const serialized = [ this.txTreeHeight, - ...toTruncField(this.txsEffectsHash), - ...toTruncField(this.inHash), - ...toTruncField(this.outHash), + toTruncField(this.txsEffectsHash), + toTruncField(this.inHash), + toTruncField(this.outHash), ]; if (serialized.length !== CONTENT_COMMITMENT_LENGTH) { throw new Error(`Expected content commitment to have 4 fields, but it has ${serialized.length} fields`); diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts index d337897f3bd0..12c8365c7375 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts @@ -10,8 +10,8 @@ import { L2Actor, computeAuthWitMessageHash, } from '@aztec/aztec.js'; -import { sha256 } from '@aztec/foundation/crypto'; -import { serializeToBuffer, toTruncField } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; +import { serializeToBuffer } from '@aztec/foundation/serialize'; import { TokenBridgeContract, TokenContract } from '@aztec/noir-contracts.js'; import { toFunctionSelector } from 'viem/utils'; @@ -157,14 +157,12 @@ describe('e2e_cross_chain_messaging', () => { await crossChainTestHarness.makeMessageConsumable(msgLeaf); // 3. Consume L1 -> L2 message and mint private tokens on L2 - const content = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), - serializeToBuffer(...[secretHashForL2MessageConsumption, new Fr(bridgeAmount)]), - ]), - ), - )[0]; + const content = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[secretHashForL2MessageConsumption, new Fr(bridgeAmount)]), + ]), + ); const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), new L2Actor(l2Bridge.address, 1), @@ -237,14 +235,12 @@ describe('e2e_cross_chain_messaging', () => { // Wait for the message to be available for consumption await crossChainTestHarness.makeMessageConsumable(msgLeaf); - const content = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), - serializeToBuffer(...[ownerAddress, new Fr(bridgeAmount)]), - ]), - ), - )[0]; + const content = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[ownerAddress, new Fr(bridgeAmount)]), + ]), + ); const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), new L2Actor(l2Bridge.address, 1), diff --git a/yarn-project/end-to-end/src/e2e_outbox.test.ts b/yarn-project/end-to-end/src/e2e_outbox.test.ts index 98f1f3e655ef..2e1a5414ec4c 100644 --- a/yarn-project/end-to-end/src/e2e_outbox.test.ts +++ b/yarn-project/end-to-end/src/e2e_outbox.test.ts @@ -6,9 +6,9 @@ import { EthAddress, Fr, SiblingPath, - sha256, } from '@aztec/aztec.js'; -import { toTruncField, truncateAndPad } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; +import { truncateAndPad } from '@aztec/foundation/serialize'; import { SHA256 } from '@aztec/merkle-tree'; import { TestContract } from '@aztec/noir-contracts.js'; @@ -103,17 +103,15 @@ describe('E2E Outbox Tests', () => { } function makeL2ToL1Message(recipient: EthAddress, content: Fr = Fr.ZERO): Fr { - const leaf = toTruncField( - sha256( - Buffer.concat([ - contract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - recipient.toBuffer32(), - new Fr(deployL1ContractsValues.publicClient.chain.id).toBuffer(), // chain id - content.toBuffer(), - ]), - ), - )[0]; + const leaf = sha256ToField( + Buffer.concat([ + contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + recipient.toBuffer32(), + new Fr(deployL1ContractsValues.publicClient.chain.id).toBuffer(), // chain id + content.toBuffer(), + ]), + ); return leaf; } diff --git a/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts b/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts index 581e2e603c4f..ea63222825d3 100644 --- a/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts @@ -14,8 +14,8 @@ import { computeAuthWitMessageHash, computeMessageSecretHash, } from '@aztec/aztec.js'; -import { sha256 } from '@aztec/foundation/crypto'; -import { serializeToBuffer, toTruncField } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; +import { serializeToBuffer } from '@aztec/foundation/serialize'; import { InboxAbi, OutboxAbi } from '@aztec/l1-artifacts'; import { TestContract } from '@aztec/noir-contracts.js'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; @@ -152,14 +152,12 @@ describe('e2e_public_cross_chain_messaging', () => { await crossChainTestHarness.makeMessageConsumable(msgLeaf); - const content = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), - serializeToBuffer(...[user2Wallet.getAddress(), new Fr(bridgeAmount)]), - ]), - ), - )[0]; + const content = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[user2Wallet.getAddress(), new Fr(bridgeAmount)]), + ]), + ); const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), new L2Actor(l2Bridge.address, 1), @@ -206,14 +204,12 @@ describe('e2e_public_cross_chain_messaging', () => { await crossChainTestHarness.makeMessageConsumable(msgLeaf); // Wrong message hash - const content = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), - serializeToBuffer(...[secretHash, new Fr(bridgeAmount)]), - ]), - ), - )[0]; + const content = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[secretHash, new Fr(bridgeAmount)]), + ]), + ); const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), new L2Actor(l2Bridge.address, 1), @@ -260,17 +256,15 @@ describe('e2e_public_cross_chain_messaging', () => { content: content.toString() as Hex, }; - const leaf = toTruncField( - sha256( - Buffer.concat([ - testContract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - recipient.toBuffer32(), - new Fr(crossChainTestHarness.publicClient.chain.id).toBuffer(), // chain id - content.toBuffer(), - ]), - ), - )[0]; + const leaf = sha256ToField( + Buffer.concat([ + testContract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + recipient.toBuffer32(), + new Fr(crossChainTestHarness.publicClient.chain.id).toBuffer(), // chain id + content.toBuffer(), + ]), + ); const [l2MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( l2TxReceipt.blockNumber!, diff --git a/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts b/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts index 0453e64f68bb..1a6365f0c3e4 100644 --- a/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts +++ b/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts @@ -16,9 +16,8 @@ import { computeMessageSecretHash, deployL1Contract, retryUntil, - sha256, } from '@aztec/aztec.js'; -import { toTruncField } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; import { InboxAbi, OutboxAbi, @@ -364,27 +363,23 @@ export class CrossChainTestHarness { } getL2ToL1MessageLeaf(withdrawAmount: bigint, callerOnL1: EthAddress = EthAddress.ZERO): Fr { - const content = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), - this.ethAccount.toBuffer32(), - new Fr(withdrawAmount).toBuffer(), - callerOnL1.toBuffer32(), - ]), - ), - )[0]; - const leaf = toTruncField( - sha256( - Buffer.concat([ - this.l2Bridge.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - this.tokenPortalAddress.toBuffer32() ?? Buffer.alloc(32, 0), - new Fr(this.publicClient.chain.id).toBuffer(), // chain id - content.toBuffer(), - ]), - ), - )[0]; + const content = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + this.ethAccount.toBuffer32(), + new Fr(withdrawAmount).toBuffer(), + callerOnL1.toBuffer32(), + ]), + ); + const leaf = sha256ToField( + Buffer.concat([ + this.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + this.tokenPortalAddress.toBuffer32() ?? Buffer.alloc(32, 0), + new Fr(this.publicClient.chain.id).toBuffer(), // chain id + content.toBuffer(), + ]), + ); return leaf; } diff --git a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts index 7f4aed845eb0..7fdfcb776902 100644 --- a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts +++ b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts @@ -9,8 +9,7 @@ import { computeAuthWitMessageHash, } from '@aztec/aztec.js'; import { deployL1Contract } from '@aztec/ethereum'; -import { sha256 } from '@aztec/foundation/crypto'; -import { toTruncField } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; import { InboxAbi, UniswapPortalAbi, UniswapPortalBytecode } from '@aztec/l1-artifacts'; import { UniswapContract } from '@aztec/noir-contracts.js/Uniswap'; @@ -247,61 +246,53 @@ export const uniswapL1L2TestSuite = ( .send() .wait(); - const swapPrivateContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from( - toFunctionSelector( - 'swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', - ).substring(2), - 'hex', - ), - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - new Fr(uniswapFeeTier).toBuffer(), - daiCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(minimumOutputAmount).toBuffer(), - secretHashForRedeemingDai.toBuffer(), - secretHashForDepositingSwappedDai.toBuffer(), - ownerEthAddress.toBuffer32(), - ]), - ), - )[0]; - - const swapPrivateLeaf = toTruncField( - sha256( - Buffer.concat([ - uniswapL2Contract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - EthAddress.fromString(uniswapPortal.address).toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - swapPrivateContent.toBuffer(), - ]), - ), - )[0]; - - const withdrawContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), - uniswapPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - uniswapPortalAddress.toBuffer32(), - ]), - ), - )[0]; - - const withdrawLeaf = toTruncField( - sha256( - Buffer.concat([ - wethCrossChainHarness.l2Bridge.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - withdrawContent.toBuffer(), - ]), - ), - )[0]; + const swapPrivateContent = sha256ToField( + Buffer.concat([ + Buffer.from( + toFunctionSelector( + 'swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', + ).substring(2), + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + secretHashForRedeemingDai.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ); + + const swapPrivateLeaf = sha256ToField( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPrivateContent.toBuffer(), + ]), + ); + + const withdrawContent = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ); + + const withdrawLeaf = sha256ToField( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ); // ensure that user's funds were burnt await wethCrossChainHarness.expectPrivateBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); @@ -483,61 +474,53 @@ export const uniswapL1L2TestSuite = ( // 4.2 Call swap_public from user2 on behalf of owner const uniswapL2Interaction = await action.send().wait(); - const swapPublicContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from( - toFunctionSelector( - 'swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', - ).substring(2), - 'hex', + const swapPublicContent = sha256ToField( + Buffer.concat([ + Buffer.from( + toFunctionSelector('swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)').substring( + 2, ), - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - new Fr(uniswapFeeTier).toBuffer(), - daiCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(minimumOutputAmount).toBuffer(), - ownerAddress.toBuffer(), - secretHashForDepositingSwappedDai.toBuffer(), - ownerEthAddress.toBuffer32(), - ]), - ), - )[0]; - - const swapPublicLeaf = toTruncField( - sha256( - Buffer.concat([ - uniswapL2Contract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - EthAddress.fromString(uniswapPortal.address).toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - swapPublicContent.toBuffer(), - ]), - ), - )[0]; - - const withdrawContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), - uniswapPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - uniswapPortalAddress.toBuffer32(), - ]), - ), - )[0]; - - const withdrawLeaf = toTruncField( - sha256( - Buffer.concat([ - wethCrossChainHarness.l2Bridge.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - withdrawContent.toBuffer(), - ]), - ), - )[0]; + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + ownerAddress.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ); + + const swapPublicLeaf = sha256ToField( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPublicContent.toBuffer(), + ]), + ); + + const withdrawContent = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ); + + const withdrawLeaf = sha256ToField( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ); // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!) await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); @@ -863,61 +846,53 @@ export const uniswapL1L2TestSuite = ( .send() .wait(); - const swapPrivateContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from( - toFunctionSelector( - 'swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', - ).substring(2), - 'hex', - ), - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - new Fr(uniswapFeeTier).toBuffer(), - daiCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(minimumOutputAmount).toBuffer(), - secretHashForRedeemingDai.toBuffer(), - secretHashForDepositingSwappedDai.toBuffer(), - ownerEthAddress.toBuffer32(), - ]), - ), - )[0]; - - const swapPrivateLeaf = toTruncField( - sha256( - Buffer.concat([ - uniswapL2Contract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - EthAddress.fromString(uniswapPortal.address).toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - swapPrivateContent.toBuffer(), - ]), - ), - )[0]; - - const withdrawContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), - uniswapPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - uniswapPortalAddress.toBuffer32(), - ]), - ), - )[0]; - - const withdrawLeaf = toTruncField( - sha256( - Buffer.concat([ - wethCrossChainHarness.l2Bridge.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - withdrawContent.toBuffer(), - ]), - ), - )[0]; + const swapPrivateContent = sha256ToField( + Buffer.concat([ + Buffer.from( + toFunctionSelector( + 'swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', + ).substring(2), + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + secretHashForRedeemingDai.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ); + + const swapPrivateLeaf = sha256ToField( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPrivateContent.toBuffer(), + ]), + ); + + const withdrawContent = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ); + + const withdrawLeaf = sha256ToField( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ); const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( withdrawReceipt.blockNumber!, @@ -1002,61 +977,53 @@ export const uniswapL1L2TestSuite = ( .send() .wait(); - const swapPublicContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from( - toFunctionSelector( - 'swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', - ).substring(2), - 'hex', + const swapPublicContent = sha256ToField( + Buffer.concat([ + Buffer.from( + toFunctionSelector('swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)').substring( + 2, ), - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - new Fr(uniswapFeeTier).toBuffer(), - daiCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(minimumOutputAmount).toBuffer(), - ownerAddress.toBuffer(), - secretHashForDepositingSwappedDai.toBuffer(), - ownerEthAddress.toBuffer32(), - ]), - ), - )[0]; - - const swapPublicLeaf = toTruncField( - sha256( - Buffer.concat([ - uniswapL2Contract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - EthAddress.fromString(uniswapPortal.address).toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - swapPublicContent.toBuffer(), - ]), - ), - )[0]; - - const withdrawContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), - uniswapPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - uniswapPortalAddress.toBuffer32(), - ]), - ), - )[0]; - - const withdrawLeaf = toTruncField( - sha256( - Buffer.concat([ - wethCrossChainHarness.l2Bridge.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - withdrawContent.toBuffer(), - ]), - ), - )[0]; + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + ownerAddress.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ); + + const swapPublicLeaf = sha256ToField( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPublicContent.toBuffer(), + ]), + ); + + const withdrawContent = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ); + + const withdrawLeaf = sha256ToField( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ); const [swapPublicL2MessageIndex, swapPublicSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( withdrawReceipt.blockNumber!, diff --git a/yarn-project/foundation/src/crypto/sha256/index.ts b/yarn-project/foundation/src/crypto/sha256/index.ts index 6054e78e834b..0f6fb259e85c 100644 --- a/yarn-project/foundation/src/crypto/sha256/index.ts +++ b/yarn-project/foundation/src/crypto/sha256/index.ts @@ -1,3 +1,10 @@ import { default as hash } from 'hash.js'; +import { Fr } from '../../fields/fields.js'; +import { truncateAndPad } from '../../serialize/free_funcs.js'; + export const sha256 = (data: Buffer) => Buffer.from(hash.sha256().update(data).digest()); + +export const sha256Trunc = (data: Buffer) => truncateAndPad(sha256(data)); + +export const sha256ToField = (data: Buffer) => Fr.fromBuffer(sha256Trunc(data)); diff --git a/yarn-project/foundation/src/serialize/free_funcs.test.ts b/yarn-project/foundation/src/serialize/free_funcs.test.ts index 1f6133683e4d..b7778fffac10 100644 --- a/yarn-project/foundation/src/serialize/free_funcs.test.ts +++ b/yarn-project/foundation/src/serialize/free_funcs.test.ts @@ -21,7 +21,7 @@ describe('buffer to fields and back', () => { const originalBuffer = Buffer.concat([Buffer.alloc(1), randomBytes(31)]); // Serialize the buffer to one field - const field = toTruncField(originalBuffer)[0]; + const field = toTruncField(originalBuffer); // Deserialize the field back to a buffer const reconstructedBuffer = fromTruncField(field); diff --git a/yarn-project/foundation/src/serialize/free_funcs.ts b/yarn-project/foundation/src/serialize/free_funcs.ts index 17260de202ed..319112ebede8 100644 --- a/yarn-project/foundation/src/serialize/free_funcs.ts +++ b/yarn-project/foundation/src/serialize/free_funcs.ts @@ -165,14 +165,16 @@ export function truncateAndPad(buf: Buffer): Buffer { * @param buf - 32 or 31 bytes of data * @returns 1 field element */ -export function toTruncField(buf: Buffer): [Fr] { +export function toTruncField(buf: Buffer): Fr { if (buf.length !== 32 && buf.length !== 31) { throw new Error('Buffer must be 31 or 32 bytes'); } if ((buf.length == 32 && buf[0] == 0) || buf.length == 31) { - return [Fr.fromBuffer(buf)]; + return Fr.fromBuffer(buf); } else { - return [Fr.fromBuffer(buf.subarray(0, 31))]; + // Note: safer to NOT truncate here, all inputs are expected to be truncated + // from Noir or L1 Contracts or Class.hash() methods + throw new Error(`Number ${toBigInt(buf)} does not fit in 31 byte truncated buffer`); } } diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index 443a294102b4..2d637f41e52e 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -818,7 +818,7 @@ export function mapSha256HashFromNoir(hash: Field): Buffer { * @returns The hash as it is represented in Noir (1 field, truncated). */ export function mapSha256HashToNoir(hash: Buffer): Field { - return mapFieldToNoir(toTruncField(hash)[0]); + return mapFieldToNoir(toTruncField(hash)); } /** diff --git a/yarn-project/simulator/src/client/private_execution.ts b/yarn-project/simulator/src/client/private_execution.ts index da23ae8daa83..b5698d2dea7c 100644 --- a/yarn-project/simulator/src/client/private_execution.ts +++ b/yarn-project/simulator/src/client/private_execution.ts @@ -3,7 +3,6 @@ import { FunctionArtifactWithDebugMetadata, decodeReturnValues } from '@aztec/fo import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; -import { toTruncField } from '@aztec/foundation/serialize'; import { extractReturnWitness } from '../acvm/deserialize.js'; import { Oracle, acvm, extractCallStack } from '../acvm/index.js'; @@ -47,9 +46,9 @@ export async function executePrivateFunction( const encryptedLogs = context.getEncryptedLogs(); const unencryptedLogs = context.getUnencryptedLogs(); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) --> set this in Noir - publicInputs.encryptedLogsHash = toTruncField(encryptedLogs.hash())[0]; + publicInputs.encryptedLogsHash = Fr.fromBuffer(encryptedLogs.hash()); publicInputs.encryptedLogPreimagesLength = new Fr(encryptedLogs.getSerializedLength()); - publicInputs.unencryptedLogsHash = toTruncField(unencryptedLogs.hash())[0]; + publicInputs.unencryptedLogsHash = Fr.fromBuffer(unencryptedLogs.hash()); publicInputs.unencryptedLogPreimagesLength = new Fr(unencryptedLogs.getSerializedLength()); const callStackItem = new PrivateCallStackItem(contractAddress, functionData, publicInputs); diff --git a/yarn-project/simulator/src/test/utils.ts b/yarn-project/simulator/src/test/utils.ts index 081e4320a53e..f8f5b6b41660 100644 --- a/yarn-project/simulator/src/test/utils.ts +++ b/yarn-project/simulator/src/test/utils.ts @@ -1,8 +1,7 @@ import { L1Actor, L1ToL2Message, L2Actor } from '@aztec/circuit-types'; import { AztecAddress, EthAddress, Fr } from '@aztec/circuits.js'; import { computeMessageSecretHash } from '@aztec/circuits.js/hash'; -import { sha256 } from '@aztec/foundation/crypto'; -import { toTruncField } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; /** * Test utility function to craft an L1 to L2 message. @@ -22,7 +21,7 @@ export const buildL1ToL2Message = ( const selectorBuf = Buffer.from(selector, 'hex'); const contentBuf = Buffer.concat([selectorBuf, ...contentPreimage.map(field => field.toBuffer())]); - const content = toTruncField(sha256(contentBuf))[0]; + const content = sha256ToField(contentBuf); const secretHash = computeMessageSecretHash(secret); // Eventually the kernel will need to prove the kernel portal pair exists within the contract tree, From e407e6f2d005beebe7a3c66f7bbb8a7c91c20620 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 22 Mar 2024 15:00:17 +0000 Subject: [PATCH 10/13] fix --- yarn-project/simulator/src/public/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index c60e6d89502a..e232b2ecd01d 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -247,7 +247,7 @@ describe('ACIR public execution simulator', () => { describe('Parent/Child contracts', () => { it('calls the public entry point in the parent', async () => { const parentContractAddress = AztecAddress.random(); - const parentEntryPointFn = ParentContractArtifact.functions.find(f => f.name === 'pubEntryPoint')!; + const parentEntryPointFn = ParentContractArtifact.functions.find(f => f.name === 'pub_entry_point')!; const parentEntryPointFnSelector = FunctionSelector.fromNameAndParameters( parentEntryPointFn.name, parentEntryPointFn.parameters, From eb814d209e0c873d19b3b2c3df4b845bb9eafb22 Mon Sep 17 00:00:00 2001 From: MirandaWood Date: Fri, 22 Mar 2024 16:24:35 +0000 Subject: [PATCH 11/13] chore: cleanup, address comments --- .../messagebridge/frontier_tree/Frontier.sol | 2 +- .../crates/types/src/content_commitment.nr | 8 ++--- .../src/structs/content_commitment.ts | 29 ++++++++++--------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol b/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol index cb2ee1f36aff..650dfbd30a1a 100644 --- a/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol +++ b/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol @@ -36,7 +36,7 @@ contract FrontierMerkle is IFrontier { uint256 level = _computeLevel(index); bytes32 right = _leaf; for (uint256 i = 0; i < level; i++) { - right = Hash.sha256ToField(bytes.concat(frontier[i], bytes32(right))); + right = Hash.sha256ToField(bytes.concat(frontier[i], right)); } frontier[level] = right; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr b/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr index 8417fa0ea792..57ae95f11996 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr @@ -14,10 +14,10 @@ impl Serialize for ContentCommitment { fn serialize(self) -> [Field; CONTENT_COMMITMENT_LENGTH] { let mut fields: BoundedVec = BoundedVec::new(); - fields.extend_from_array([self.tx_tree_height]); - fields.extend_from_array([self.txs_effects_hash]); - fields.extend_from_array([self.in_hash]); - fields.extend_from_array([self.out_hash]); + fields.push(self.tx_tree_height); + fields.push(self.txs_effects_hash); + fields.push(self.in_hash); + fields.push(self.out_hash); fields.storage } diff --git a/yarn-project/circuits.js/src/structs/content_commitment.ts b/yarn-project/circuits.js/src/structs/content_commitment.ts index b2f5ac0ae92b..e95bd6f9189b 100644 --- a/yarn-project/circuits.js/src/structs/content_commitment.ts +++ b/yarn-project/circuits.js/src/structs/content_commitment.ts @@ -1,11 +1,5 @@ import { Fr } from '@aztec/foundation/fields'; -import { - BufferReader, - FieldReader, - fromTruncField, - serializeToBuffer, - toTruncField, -} from '@aztec/foundation/serialize'; +import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { CONTENT_COMMITMENT_LENGTH } from '../constants.gen.js'; @@ -16,12 +10,21 @@ export class ContentCommitment { if (txsEffectsHash.length !== NUM_BYTES_PER_SHA256) { throw new Error(`txsEffectsHash buffer must be ${NUM_BYTES_PER_SHA256} bytes`); } + if (txsEffectsHash[0] !== 0) { + throw new Error(`txsEffectsHash buffer should be truncated and left padded`); + } if (inHash.length !== NUM_BYTES_PER_SHA256) { throw new Error(`inHash buffer must be ${NUM_BYTES_PER_SHA256} bytes`); } + if (inHash[0] !== 0) { + throw new Error(`inHash buffer should be truncated and left padded`); + } if (outHash.length !== NUM_BYTES_PER_SHA256) { throw new Error(`outHash buffer must be ${NUM_BYTES_PER_SHA256} bytes`); } + if (outHash[0] !== 0) { + throw new Error(`outHash buffer should be truncated and left padded`); + } } toBuffer() { @@ -31,9 +34,9 @@ export class ContentCommitment { toFields(): Fr[] { const serialized = [ this.txTreeHeight, - toTruncField(this.txsEffectsHash), - toTruncField(this.inHash), - toTruncField(this.outHash), + Fr.fromBuffer(this.txsEffectsHash), + Fr.fromBuffer(this.inHash), + Fr.fromBuffer(this.outHash), ]; if (serialized.length !== CONTENT_COMMITMENT_LENGTH) { throw new Error(`Expected content commitment to have 4 fields, but it has ${serialized.length} fields`); @@ -56,9 +59,9 @@ export class ContentCommitment { const reader = FieldReader.asReader(fields); return new ContentCommitment( reader.readField(), - fromTruncField(reader.readField()), - fromTruncField(reader.readField()), - fromTruncField(reader.readField()), + reader.readField().toBuffer(), + reader.readField().toBuffer(), + reader.readField().toBuffer(), ); } From 5d384921783fc45b50ce55e6f2539655a6ff8482 Mon Sep 17 00:00:00 2001 From: MirandaWood Date: Fri, 22 Mar 2024 17:19:50 +0000 Subject: [PATCH 12/13] fix: fix merged incorrect name --- yarn-project/end-to-end/src/e2e_static_calls.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_static_calls.test.ts b/yarn-project/end-to-end/src/e2e_static_calls.test.ts index 458ca88a76a1..b51892a656c6 100644 --- a/yarn-project/end-to-end/src/e2e_static_calls.test.ts +++ b/yarn-project/end-to-end/src/e2e_static_calls.test.ts @@ -23,7 +23,7 @@ describe('e2e_static_calls', () => { describe('parent calls child', () => { it('performs legal private to private static calls', async () => { // We create a note in the set, so... - await childContract.methods.privateSetValue(42n, wallet.getCompleteAddress().address).send().wait(); + await childContract.methods.private_set_value(42n, wallet.getCompleteAddress().address).send().wait(); // ...this call doesn't fail due to get_notes returning 0 notes await parentContract.methods .private_static_call(childContract.address, childContract.methods.private_get_value.selector, [ @@ -36,7 +36,7 @@ describe('e2e_static_calls', () => { it('performs legal (nested) private to private static calls', async () => { // We create a note in the set, so... - await childContract.methods.privateSetValue(42n, wallet.getCompleteAddress().address).send().wait(); + await childContract.methods.private_set_value(42n, wallet.getCompleteAddress().address).send().wait(); // ...this call doesn't fail due to get_notes returning 0 notes await parentContract.methods .private_nested_static_call(childContract.address, childContract.methods.private_get_value.selector, [ From a504f6355a195831b49cd1c49e8f426f8f08e7e2 Mon Sep 17 00:00:00 2001 From: MirandaWood Date: Fri, 22 Mar 2024 18:38:43 +0000 Subject: [PATCH 13/13] chore: update fixtures --- .../contract/__snapshots__/contract_class.test.ts.snap | 10 +++++----- .../src/__snapshots__/index.test.ts.snap | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap b/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap index dfc593aef670..3b6fb55754f3 100644 --- a/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap +++ b/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap @@ -9,18 +9,18 @@ exports[`ContractClass creates a contract class from a contract compilation arti "selector": { "value": 2381782501 }, - "bytecode": "0x1f8b08000000000000ffed9d079c1545beef7b8621e87146cc028651519078e630648483398b2092c330e41c86282819441104910c43ce8860d8e866379936e8aebb77f7eedebcf7ed0b9ff73ef7bef7ee7d6fefeb3aa7fe6f7e14d5e39cb16bfc8d547f3e35a7fa37d55ddffa757575a8eeaebc203bfd290c793ade200c2d830b27f97f5aff263fdf5412e3ba922e39f3ea09677e3de16c504f380bea0967c37ac2d9a89e7036ae279c4dea09e725f584f3d27ac299a8279c97d513cec27ac259544f382faf279c4deb09e715f584f3ca7ac279553de1bcba9e705e534f38afad279cd7d513ceebeb0967b37ac2d9bc9e70b6a8279c37d413ce1beb09e74df584f3e67ac2595c4f386fa9279cb7d613cedb62e46c0b9c72cffe76fd7b87fe6da57f5bebdf3bf56f1bfddb5697b140cfb70b43fb3074084347e37fca1875e33e15864ec6ff4ac3d0390c5dc2d055ffaf58ffaf5b18ba87a147187a86a15718ee0a43ef30f4d17ef40dc3dd61b8270cf786e1be30dc1f8607c2f060181e0ac3c36178240c8f86e1b1303c1e8627c2d02f0c4f86a17f180684e1a9300c0cc3d3611864b00c0ec390300c0dc3b0300c0fc388308c0cc3a8308c0e435918c684a13c0c63c3302e0ce3c330210c13c330290c93c330250c53c3302d0cd3c330230c33c3302b0cb3c330270c1561981b867961986f78b6200c0bc3b0280ccf189c8bc3b0240ccf86e1b9302c0dc3b2302c0fc38a30ac0cc3aa30ac0ec39a30ac0dc3f36158178617c2f06218d687e1a5306c08c3c630bc1c864d61d81c8657c2b0250caf86616b18b685617b18768461a766911d6157187687614f18f686a1320cfbc2b03f0c07c270300c87c270380c47c270340cc7c2703c0c27c270320ca7c2703a0caf85e14c185e0fc3d9309c0bc31b6178330c6f85e1ed307c250c5f0dc3d7c2f0f5307c230cdf0cc33b61f85618be1d86ef84e1bb61f85e18be1f861f84e1dd30fc300c3f0ac38fc3f09330fcd4f0fcbd30bc1f860fc2f0a1d63ed2bf3fd3bf3fd7bfbfd0bfbfd4bf1febdf4ff4efaff4efaff5efa7faf737faf7b7faf7aff4efeff4efeff5ef5febdf3fe8df3feadfbfd1bf7fab7fff4efffebdfefd07fdfb8ffaf79ff4afeac75bde221b6f12544de920a636a7745c99ba8f2f669afd84aa0faa81fe9ffc166bbd40cfcb6f9ed61beaf98686de48cf3732d6d344cf3731f4223d5f64e84df57c5343bf52cf5f69e857ebf9ab0dfd163d7f0be809fdbf6cc1b23f4a6ba0a53cd0a4fee583d6506b0d406b24ab03adb1d61a8226dbb711689768ad3168976aad096809ad5d02da655abb14b442ad25402bd2da65a05daeb542d09a6aad08b42bb4763968576aad29685769ed0ad0aed6da95a05da3b5ab40bb566b5783769dd6ae01ed7aad5d0b5a33ad5d075a73ad5d0f9adec58266a0dda0b5e6a0dda8b516a0dda4b51b40bb596b378256acb59b40bb456b378376abd68a41bb4d6bb780d6526bb78226e70ab7694dd53369fb32cb683d1fb4db65ff06ed0ed9b7416b25fb3568ad659f06ed4ec85bb436b28f83d6566b52c7d5ffbae8783a88ab7d4b95abf5768d7bbde19ad57abbc7bfdea46a2f7b04555ea7219faee0554f1d8ff1798612cc3b4f07c947f402883f0069259df821ed94b0abb6a79b8ef7ac66b92ec6724590a69ba5fce920def2773778ba1bcc6a9bf4028ef8eb6ca7a4afb3359e72aeb30321ad59f7e498f965acb30f0387833a5beaeb6c8da79ceb6c39a435eb9e9cbf7d19ebec60e0705067bbb9a9b3a9a4afb3d97b264160af7b722df165acb3e38123fe3adbd9d7d99a4f39d7d9e720ad59f7e4baf6cb58672b8023fe3adbb59b3f37a8f194739d5d0f69cdba27f758be8c7576397038a8b3e5be9dadf194739ddd0969cdba27f7fbbe8c75762370c45f67bb3baab39d7c9d0db2fd5f4160af7b72eff9cb5867f70047fc75b6dcdf9fadf994739d7d1bd29a754ffa41be8c75f6a48eab7e868f743fc30da0fd4c6b3782f673addd04da2fb4763368bf84fe42d13e96be44d03ed1daada0fd4a6bb781f66ba3ef55699f6aed76d07ea3b53b40fbadd65a81f6575a6b0ddaefb4762768bfd75a1bd0fe5a6b6d41fb83d6da81f647adb507ed6fb4d601b4bfd55a47d0fe4e6b49d0fe5e6b25a0fd83d652a0fda3d63a81f64f5a2b05ed4f5aebac35d54f297d5fef6aad0970a583f8ea68023c9029cf984f43bca35b9e6411f0605e25f1e7d54995fdbc87ad3ea3ec25c0937250f604e451139e14f0748a9f27f38e5f69fcebcd6ce3a4e16902f24a42b93a3b28571ee425eb9679c9af0834dca73b5b18633fcf082fbcf2202f59b7cc770146d1b08d913657f61f758cf967e075b02f65ce33243f797759384a409734d7b7a862fb2f5a2b84ff637bdbc9d01cd5cb4cbd90bc64dd325f0a8c529e4e75cf98aa2963ca6074d546e4415eb26e9f77d576907807e0e9e688c76cd324ef6e7590771723ef12236f6c3b65aaeed8d605981d5c6f957c11d75b78fec070bd75455e555af3ba49dae15cafb73a1bcb315e6f35caabe270b03f64ea40378343e64bc0bbee11de7503ef24cdede09d8373cf8c775d0d1e994f018fb463a5c0d3a18e793a10e48de7b0b2ddf05a0acf035c6daf0e06a3ccdbb65717604c59181d9c13a6aa3b469600a368783f2ae9c8b3a8ed9a24c9dbc57525be4b21e7e6e6b54d01a4f93ff9d95fd556b6cf73ca96c27367996a7acd1bff764a2571ffa8098fe37da8c4517d4ce2fd9bbf04f1d635b35d32db9ba87b3caedaf2a4c123f3929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c523fd09f8dc96a4eb44c2683effe6ea3e7fe65b28b22efdabfa75de817e9df8fb2d5249ecfb93e7205a19652e80341fe555a5fdae8eab670ea49f0a9fb5329fbf72d96787cf63a6615ef2c367ad705b323cef541c5bded9efd2b8e86fbb3cc87e53c77cf6b393c55317cf3fa3a77986a7f81cf89d068faaa7ff915fc5e6a2ef2fd7be48f44ae271f6ed1505f6ba1eff76499dd7679d1f9cdf7ee071c6d5f33bd2564b7f793723ef0248f37b788e4a9ead92718692c672f8dc8fac5b9669057a7763dd4df5b2c2d1d0587f292c2b69fe086dea4aa8ab0edaca54aecfae63bf79fcc7e16c3f7e32079e0ec0e3a29d7174be91c47d20ee7e7cf3f934db798ca4c167fb1c3c5759edf34e929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c563f6b5e2fbb525248ca2397ef621d39fd15aaf4bd6affa7566e757e5ebba1f4efa9c5a1b65c67747cfe557a59da7e385c185cf3b446d4b57dfa788da96921f7e7ba603f0b8e8d7cd83bc64dd1d2d5e48bc38b6bcb3fdf8f17b5cd58f9f347c2db178ea6a7fc53e56f414f7d794c1837da351dff6e968688ef6f16aeb85e487fb5247d0248eef47bbd8ce782c319feb91fcb0fffa25ed6dd3c0d5b64f255db61bf8dd94747061fdc6efa96c86b66f8b8ee3331cf8ecc841cbff65aaae9f5afc5365ee157f9933dbf72ee04c433e98776f608d29ef12cc3b4f07c947f402881fc8af4a2be9c40ff15ad8d53e22df80417673b994b15c11a4e969297f3a88b7fcbd0c9e5e06b3da26dba09e1d84e3bfab36a9678447adc0234983e741ae9ec933db48f3f9467c6eaf919106cf5924cd4968a354596ccf8fda9e3974751c8b7ae6d0766edc0118cd329acf795eeccf697d03da8bb89fd3fa06d4217c4e2b30d6df1ad62f5c8d82e8638ba4f9b6b17ef39c5c96c1e7c024cdf7a0bdf8975a9c937f51d757b673725c2eaaec8a19bf83968e9119eb04b2e07982a479dfd866dd23b8bb5896fd286259f1cafc56586170a17f6ebeb396dde77b1965917add13ca22693e31ce01e33f6fc99e03bafaa61c9e7ba8f576b49455d2fc16f6b5dfc1399e6c27dc6fff6cf9bf4cd59d03e2788e7de22f7312f719d9be7d2c79f705d698f22ec175c939605fc3830288ff2768d3259da415af855ded23721e85ece672dd8ce58a204d6f4bf9d341bce5ef63f0f43198d536f903d4b33fc339a0abb6ba778447adc1234983f7146ddf01b5ddeba8ab7345f3fbc245c185f709f038e9e6bcc9fe9e90795fcd768ed0dae0c773847f83763661496bde2f94e3659ccf0de3bb12a590ef7f58f24dc7ec6757f02d0df3785ef045e6ede03be1997744f0bb82c280531ae2f8ed70592e1f185d7c6f3d119cff7de0cf62c46fb0cb720d80d1c536ccf5fbc4a5c028cb1500a38bf7bff01bf93561ec048cb82f0aa38bef92d6f67b8e78dddd081899deabc2fbc78d81d1c5b1abb6efd3e031b709fcba1a3b24990363476094e52e014617f7aff07ca3268c78ee22cb5d0a8c2eee33e73a060b7e1f1aefff08a38b73c05caf51f05e952c771930f670c4d83d07c61ec088f71c84d1c5f56402f2ad09634f60445e6174d0079061ec990323de2b97e52e07c6bb1c31f6ca81f12e6094e59a02a38bfbf909c8b7268cbd815196bb02181d5ceb67187be7c088d7c4b2dc95c09876c4d82707c63430ca725701a38bebf684c1f0598c7d8151f4ab81f16e478c7d7360bc1b1865b96b80f11e478c77e7c0780f30ca72d702e3bd8e18efc981f15e6094e5ae03c6fb1c31de9b03e37dc028cb5d0f8cf73b62bc2f07c6fb8151966b068c0f3862bc3f07c6078051966b0e8c0f3a627c2007c6078151966b018c0f39627c3007c687805196bb01181f76c4f8500e8c0f03a32c7723303ee288f1e11c181f014659ee26607cd411e32339303e0a8cb2dccdc0f89823c64773607c0c1865b962607cdc11e36339303e0e8cb2dc2dc0f88423c6c773607c021865b95b81b19f23c6277260ec078cb2dc6dc0f8a423c67e39303e098cfd2c8cfd1d313e9903637f6094e5ee04c601f13366be43d33f07c601c0f354fc3c19cf06e4c0f3945b9ecc379c0658f27a3afebc32db626050f3b23f0d3c83e2e7c96c8ba773e0118622580e3d1b1c3f63c6b34139300e069e21f1f3643c1b9c03cf10f06cb0c5b3a1f133663c1b9203e350e019163f4fc6b3a139f00c03cf865a3c1b1e3f63c6b36139300e079e11f1f3643c1b9e03cf08f06cb8c5b391f133663c1b9103e348e019153f4fc6b39139f08c02cf465a3c1b1d3f63c6b35139308e069eb2f879329e8dce81a70c3c1b6df16c4cfc8c19cfca72601c033ce5f1f3643c1b93034f397836c6e2d9d8f819339e95e7c0381678c6c5cf93f16c6c0e3ce3c0b3b116cfc63b621c9703e3780b4fdcdf171d67c96ba2a3b24f086a5e76612882e590719223c68939304e0246590efbd7273b629c9403e3646094e5b07f7d8a23c6c939304e0146590efbd7a73a629c9203e3546094e5b07f7d9a23c6a939304e0346590efbd7a73b629c9603e37460445e619ce188717a0e8c33804b96c3fef5998e1867e4c03813186539ec5f9fe58871660e8cb3805196c3fef5d98e1867e5c0381b186539ec5f9fe38871760e8c73805196c3fef50a478c737260ac0046590efbd7e73a62acc881712e30ca72d8bf3ecf11e3dc1c18e701a32c87fdebf31d31cecb81713e30ca72d8bfbec011e3fc1c181700a32c87fdeb0b1d312ec881712130ca72d8bfbec811e3c21c181701a32c87fdebcf38625c9403e333c028cb61fffa62478ccfe4c0b818186539ec5f5fe28871710e8c4b805196c36bae671d312ec981f159605ce2192f0a46e4298e8f278965c7bc9e2328fb73169ebcc04dd931afa504655faa7feb1be3b3f580717c3d60f43e7a46cff8e563f4fbb5f79189d1fbe87df48c9ed1337ac68b9db13eb4e19eb15ed4c7546d1915cfb2f879329e2dcd8167197826cb3de59631555b46c5b33c7e9e8c67cb72e0590e9e2db378e68031555b46c5b3227e9e8c67cb73e059019e2db778e68031555b46c5b3327e9e8c672b72e059099eadb078e68031555b46c5b32a7e9e8c672b73e059059eadb478e68031555b46c5b33a7e9e8c67ab72e0590d9eadb278e68031555b46c5b3267e9e8c67ab73e059039eadb678e68031555b46c5b3367e9e8c676b72e0590b9eadb178e68031555b46c5f37cfc3c19cfd6e6c0f33c78b6d6e2192be3f87ac0f86c3d60ac0f3e7a46cfc8c4e8f76bef2313a3f7d1fbe8193da367acbf8ccfd50346bfad3d232be3baf81953b932ae73ec99a37266c69f7a41af2bc66f22a494572f1a5ead35bc2a82342f807f2f3af02f0ff29575cbbce4972b734b02664779a7645ce4b5467ecf1a7ea869bdfe6d08fa78f0f4251d97b1e724fd73a04b9a597aa00f19d352261c93717dfce52da96edf96fc90672e194f67329e19643cabc9782691f1ac20e31943c6b3948c673819cfd3643c4f90f1b422e3b9878ca73d194f03329e0e643ca5643c7791f13c44c633998c6726194f3919cf3c329e11643cadc9780691f12c26e3e947c6f33019cfbd643cbdc978ba91f1b421e3e944c6338b8c673e19cf14329e95643c63c9789691f18c24e35943c633988ce749329e47c878ee23e3694bc6d39d8ca70f194f8a8c6736194f3b329ea9643c0bc878c691f18c22e36949c633848ca73f19cfa3643cf793f1a4c9787a90f12c24e32921e39943c6d3958c671a19cf2a329e3bc8782690f18c26e35942c6733b19cf50329e01643ccbc9781e23e379808ca72f194f4f329e45643c49329e0a329e2e643cd3c9782692f19491f10c23e31948c6f33819cf3a329e07c978ee26e3e945c6f30c194f1e014f22b8f09dd404fc7f1d68f9c6b28dc330ac45d5ff37683d1f96d9a8e30d2cebde00da4b3abed1b22cfab401ca92d6f1e4e79b323e615e699897fc0a81632309cf33643cbdc878ee26e379908c671d19cfe3643c03c9788691f19491f14c24e3994ec6d3858ca7828c2749c6b3888ca727194f5f329e07c8781e23e3594ec633808c672819cfed643c4bc8784693f14c20e3b9838c671519cf34329eae643c73c8784ac8781692f1f420e34993f1dc4fc6f328194f7f329e21643c2dc9784691f18c23e35940c633958ca71d19cf6c329e14194f1f329eee643c6dc978ee23e379848ce749329ec1643c6bc8784692f12c23e3194bc6b3928c670a19cf7c329e59643c9dc878da90f17423e3e94dc6732f19cfc3643cfdc8781693f10c22e3694dc633828c671e194f3919cf4c329ec9643c0f91f1dc45c6534ac6d3818ca701194f7b329e7bc8785a91f13c41c6f33419cf70329ea5643c63c8785690f14c22e3594dc633838ca73319cf5c329e8e161e07e33b6678e4fd3c59b7ccaf23c9dbc176c88c6bf9b2a3326dd2eb6aa8d72bfc925f01a4f9b071f6b76990ad0fa20bd77a1dc7ba21de6c028f36392a8b6c8f3c63fb38ce3b85ef8d06c01018fe04161e17efdb3a2ae779f530eef155371b5e99dbae08d2bc0cfe6d76e09fad6ecbbce4972b734b0266ac17c541bcf5e295f8cbf4ffc76d155f5f31fcc572bdaae331d6cba45ac716bdae8690dfab90ef361dcf8b315fb5aead7a5d32ceac706c035dd2fc33b4cbc8ac26697ff19b66db753c1d1f73661c6c1c47573cc1290df1edc0b3d5018fa37266b6cd0ea34ceb8c3215419a2d50ce1d0eca9907f9caba657e07f0c8d411785cd4839a6cf3a8b18719783a93f1cc20e3594dc633898c670519cf18329ea5643cc3c9789e26e379828ca71519cf3d643cedc9781a90f17420e32925e3b98b8ce721329ec9643c33c978cac978e691f18c20e3694dc633888c673119cf16329e7e643c0f93f1dc4bc6d39b8ca71b194f1b329e4e643cb3c878e693f14c21e35949c633968c671919cf48329e35643c83c9789e24e379848ce73e329eb6643cddc978fa90f1a4c8786693f1b423e3994ac6b3808c671c19cf28329e96643c43c878fa93f13c4ac6733f194f9a8ca70719cf42329e12329e39643c5dc978a691f1ac22e3b9838c670219cf68329e25643c43c9780690f12c27e3d94cc6f31819cf03643c7dc9787a92f12c22e34992f15490f17421e3994ec633918ca78c8c671819cf40329ec7c9781e24e3b99b8ca71719cf33643c79043c51630fcbff378326efd4e178c43b757c2b68f9963ce459f81da015e8b8ac43bdca39bec585eb469f5cbd478879a5615ef2c3b1877792f03c43c6d38b8ce76e329e07c9781e27e31948c6338c8ca78c8c672219cf74329e2e643c15643c49329e45643c3dc978fa92f13c40c6f31819cf66329ee5643c03c8788692f12c21e3194dc633818ce70e329e55643cd3c878ba92f1cc21e32921e35948c6d3838c274dc6733f19cfa3643cfdc9788690f1b424e31945c6338e8c670119cf54329e76643cb3c97852643c7dc878ba93f1b425e3b98f8ce711329e27c9780693f1ac21e31949c6b38c8c672c19cf4a329e29643cf3c9786691f17422e36943c6d38d8ca73719cfbd643c0f93f1f423e3d942c6b3988c6710194f6b329e11643cf3c878cac9786692f14c26e379888ce72e329e52329e0e643c0dc878da93f1dc43c6d38a8ce709329ea7c9788693f12c25e31943c6b3828c671219cf6a329e19643c9dc978e692f174ac1b9e52f52e1e8ef7295c38a521be0378b638f0c7513993f81e669c63692aaf76195e6d36bc2a8234dbc1bf5d0efccb837c65dd322ff97966cf1cc5ac78e4d970dbfbc14b481845dbe294a734998032cb545dfbb80b785c1c3f1cf99e69c7761b655a62f15dd2605dddeda09cb67d47e6775bf22e0ee2f5624f0dbcd863e1d953c75e487eb9326faf87ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e0781f7d9fbec7d4e7ebec9fbace3de67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e473133f8ac7896eab8b02620dd521246d176b8e5c9bc6fb434387fca33e6d310df033cbb1cf8e3a89c9967c8f71a655a1a5ce8bba4c1fd6baf8372daf61d99df0bdb2117e6ddf590d9fb5c3b66c5b34cc797eadf04a45b46c228da2eb73c99766c5970fe545d3bb617785cb4f38eca9969c72a8d322db3f82e6970ffaa74504edbbe23f395b01d2a3db367b6302b9ee53a2eac0948b79c8451b43d4e795299f71b9707e74fd5b56395c0e3a29d77e47ba61ddb679469b9c577498375759f8372daf61d9997fc7265de5d0f99bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866eff3c5e3b3e2916f260b6b02d2ad2061146daf539e4e997e8715c1f9539e319f86f83ee0a98c9d27dbefe0c0f74cbfc37ea34c2b2cbe4b1adcbff63b28a76ddf91f9fdb01dbeecccbbeb21b3af1b75c3eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c73143343dd503c2b755c5813906e2509a368956e7932df3d58199c3fe519f36988ef079e7d0efc7154cecc733b078c32adb4f82e6970ff3ae0a09cb67d47e60fc076f0cc9ed9c6ac7856e9b8b02620dd2a1246d1f6b9e5c9b463ab82f3a7eadab103c0e3a29d7754ce4c3b76d028d32a8bef9206ebea4107e5b4ed3b327f10b68367f6cc3666c5b35ac7853501e95693308ab6df2d4fa61d5b1d9c3f55d78e1d041e17edbca37266dab1434699565b7c973458570f3928a76ddf91f943b01d3cb367b6312b9e353a2eac0948b7868451b4036e7932edd89ae0fca9ba76ec10f0b868e71d9533d38e1d36cab4c6e2bba4c1ba7ad841396dfb8ecc1f86ede0993db38d59f1f4d771614d40bafe248ca2e1f9cf91f8794a13068f9aaa6bc78e38f6c7513933edd8d1c0eefb11f05dd2605d3deaa09c7990afac5be68fc276c88579773d64f63ed78e59f10cd471614d40ba81248ca21d069e63f1f394260c1e3555d78e1d73ec8fa37266dab1e381ddf763e0bba4c1fdebb88372e641beb26e993f0edb2117e6ddf590d9fb5c3b66c53348c7853501e90691308a7614784ec4ce93fdbe31f2a8a9ba76ec84637fdc9433db8e9d0cecbe9f00df250dee5f271d94330ff29575cbfc49d80e9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99b99915cf101d17d604a41b42c228da71e039153b4fb6df0179d4545dbfc329c7feb82967b6dfe17460f7fd14f82e69b0ae9e7650ce3cc857d62df3a7613b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563cc3745c5813906e1809a3682781e7b5f8794a13068f9aaaeb7778cdb13f8eca99e9773813d87d7f0d7c97345857cf3828671ee42beb96f933b01d3cb367b6312b9e113a2eac094837828451b4d3c0f37aec3cd9fe53e4515375edd8eb8efd7153ce6c3b7636b0fbfe3af82e69b0ae9e7550ce3cc857d62df367613be4c2bcbb1e327b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccdee78bc767c5334ac7853501e94691308a760678cec5ced329993078d4545dbfc339c7feb82967b6dfe18dc0eefb39f05dd2e0fef5868372e641beb26e997f03b6c3979d79773d64f675a36e987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e6266a81b8aa74cc7853501e9ca4818453b0b3c6fc6cf539a3078d454dd733b6f3af6c7513933cfedbc15d87d7f137c9734b87fbde5a09c7990afac5be6df82ede0993db38d59f194ebb8b026205d3909a3686fb8e549250c1e3555d78ebd053c5f899f27d3aebe9503cf5780e7edf8794a1c9533a9d6fb55608f6bbdcaabaf195ebd657855046990e16b0efccb837c65dd322ff97966cf1cc58c6da1b02620dd9b248ca2bd0d3c2eda0d55f6367a5db2fe8661e8d7b42adf73f1e75b8ad72c0df57a8543f22b8034e9e655699fd26c85f07fd96eaa3c670dcdd1b76f4a6cef4bc8bce45718d4d93544b5d734e8858be7fc733dee9fb5f0fc253e9e24eee798978b6f2be5facec5190b4f8c652f897adfc4c577ec54d9dbea75c9fad53e3ab1a953cf4b71df93f6a3ad51e602487303b41f53a1fdb0b515aef7cdbcc0be6fe60755ed9970156bddbc37f117ad4bba73901edb9cfefa17f7cffe505657ed62d43509b68b66dbedd27bf3fe98997711f8728ed433db751cfa38d0c23d90801beb635dee67b26edb3d8481868f6c9ee1b63e67f17190857b100137e37e3dc8f091cdb3cfdaaf8758b887107033eed7430c1fd93cfbacfd7a98857b180137e37e3dccf091cdb3cfdaaf4758b847107033eed7230c1fd93cfbacfd7a94857b140137e37e3dcaf091cdb3cfdaafcb2cdc6504dc8cfb7599e1239b679fb55f975bb8cb09b819f7eb9af69332edd78eee7f67fa49d133355577cff09c537fb2dfabcfe5f993d781c7459d72540f928eeeb966fa49cdf107ce195ee1f8038eefcb56fb5d22c9cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f33bedf8bfd2b92ee0d1246d11c3f9b9fe9cf68a7d725eb57cffeceb8c265bea924f67bca73c9264701a4f9d3f55569e76836ec5fc47ed13386e6725b9ae34fcbbce45708e5c1faefea5deda8baf58625efe2d8f24e95bbf13895bc3c5cc72541d5767ecd280f7a7a3af6fccff734cff0f4b4e3bc737d5f02791cf4c596382a67a62d386594c9f4b808d2b484729e7250ce3cc857d62df3a78047a67ce0715507038327b0f823d35c329ece643c93c8788693f1dc42c6f30419cf35643cf790f15c42c6b3988ca703194f7b329e99643ce5643c83c8786e20e379988ca729194f6f329e02329ef9643c9dc878da90f1d4c53d805c78a690f18c24e3b98d8ce749329e3bc978ae23e3b98f8c2741c6d3968ca73b19cf6c329e71643c43c8786e22e379948ce74a329e34194f23329e85643c25643cd3c878ee20e3194dc673968ce776329e01643ccdc8781e20e32924e3e949c65341c6d3858c672219cf30329e62329ec7c978ae26e3b99b8ca70919cf33643c1dc9786690f18c21e3799a8ca70519cf43643cadc8782e27e3b98b8ca70119cf3c329e52329ec9643c23c8785a93f1dc4ac6d38f8ce75a329e7bc9782e25e3e946c6338b8c672c19cf60329e1bc9781e21e3b9828ca70f194f43329e05643c29329e76643c53c9784691f1b424e3e94fc6733d19cffd643c9791f1f420e39943c6d3958c670219cf50329e9bc9781e23e3b98a8ca72f194f63329e45643c49329ee9643c65643c03c9789a93f13c48c65344c6d38b8c278f8027115cf82d9d04fcff75d0e49b2ff8bdb07ccbfaa49f51d2abe3d0cc1617ae3bdfb2eed31606f4e9249425ade3c9cf379df79d9b3cbd5e9997fc0a81e334094f2f329e22329e07c9789a93f10c24e32923e3994ec69324e35944c6d3988ca72f19cf55643c8f91f1dc4cc633948c6702194f57329e39643c3dc8782e23e3b99f8ce77a329efe643c2dc9784691f14c25e36947c69322e35940c6d3908ca70f19cf15643c8f90f1dc48c633988c672c19cf2c329e6e643c9792f1dc4bc6732d194f3f329e5bc9785a93f18c20e3994cc6534ac6338f8ca70119cf5d643c9793f1b422e379888ca70519cfd3643c63c8786690f17424e379868ca70919cfdd643c5793f13c4ec6534cc6338c8c6722194f17329e0a329e9e643c85643c0f90f13423e31940c6733b19cf59329ed1643c7790f14c23e32921e35948c6d3888c274dc6732519cfa3643c3791f10c21e31947c6339b8ca73b194f5b329e0419cf7d643cd791f1dc49c6f32419cf6d643c23c978a690f19c21e36943c6d3898c673e194f01194f6f329ea6643c0f93f1dc40c633888ca79c8c6726194f7b329e0e643c8bc9782e21e3b9878ce71a329e27c8786e21e3194ec633898ca73319cf5c329e7c8307ffafde3592ebb353fab700febf583f8cd254af4bd2c83b89eaded2094353e53deea8bc2782aa290df3c7a1bcc27e02784e38e23969f0987917427c207876ccd014e351478cc70c46993f0a8ce2df31e039e688e7b8c163e65d08f141e0d91143538c871d311e311865fe30308a7f4780e788239ea3068f997721c4878067870c4d311e74c478c86094f983c028fe1d029e438e780e1b3c66de85101f069e1d3034c5b8df11e3018351e6f703a3f87700780e38e23968f0987917427c0478b6cfd01463a523c67d06a3cc5702a3f8b70f78f639e2d96ff0987917427c1478b6d7d014e31e478c7b0d4699df038c953abe1778f63ae2a93478ccbc0b215e069eed3634c5b8cb11e36e8351e67701a3f8b71b78763be2d963f098791742bc1c3cdb69688a718723c69d06a3ccef0046f16f27f0ec74c4b3cbe031f32e84783fd084b72b68db75bc0b68db74bc33685b75bc14b45775bc13685b743c05da2b3a5e02da66f103b44d3ade11b49775bc03681b75bc1b681b74bc3b682fe9780fd0d6eb784fd05ed4f15ea0bda0e37781b64ec77b83f6bc8ef7016dad8ea7415ba3e37d415bade37783b64ac7ef016da58edf0bda0a1dbf0fb4e53a7e3f68cb74fc01d096eaf883a03da7e30f81f6ac8e3f0cda121d7f04b4f13afe28684fe9f863a0bda9e38f83f6968e3f01dadb3afe24685fd1f101a07d55c79f06ed6b3a3e18b4afebf850d0bea1e3c341fba68e8f04ed1d1d1f0ddab7747c0c68dfd6f1b1a07d47c7c781f65d1d9f00daf7747c2268dfd7f149a0fd40c72783f6ae8e4f01ed873a3e15b41fe9f834d07eace3d341fb898ecf00eda73a3e13b4f7747c1668efebf86cd03ed0f139a07da8e315a07da4e37341fb998ecf03ede73a3e1fb45fe8f802d07ea9e30b41fb58c71781f6898e3f03daaf747c3168bfd6711cf7ee373a5e1cc4dbbe7f1a544dc590b7e4a7d2fc56c71b196964d90248d350df1c55f73b8a82aaf65f8e074a93f67f3b68d2fe6f034ddaffada049fbff2a68d2fe6f014ddaff574093f67f3368d2fe6f024ddaff974193f67f2368d2fe6f004ddaff974093f67f3d68d2febf089ab4ff2f8026edff3ad0a4fd7f1eb4b48eaf054ddaff35a049fbbf1a3469ff578126edff4ad0a4fd5f019ab4ffcb4193f67f1968d2fe2f054ddaffe74093f6ff59d0a4fd5f029ab4ffe34193f6ff29d0a4fd7f133469ffdf024df6b54f419363c2dba0c931e12ba0c931e1aba0c931e16ba0c931e1eba0c931e11ba0c931e19ba08dd6f177409363c2b7409363c2b7419363c277409363c277419363c2f7409363c2f7419363c20f409363c2bba0c931e187a0c931e147a04dd7f11f8326c7849f8026c7849f8226c784f7409363c2fba0c931e103d0e498f02168724cf808343926fc0c343926fc1c343926fc02343926fc123439267c0c9a1c133e014d8e09728c68029adcaf5653f2734e4541d5940f7909533a88f79883531ae2cf40d9655a43c6730b19cf66329e6bc8782e21e3694fc6534ec6b3948c671019cf8b643c3790f17c4ac6b38d8ca72919cf21329e83643c05643c6dc878ce90f1ec24e3798b8c671519cf6d643c7792f15c47c6f332194f828ca72d19cf10329e75643c3791f1bc4ac6732519cf01329efd643c8dc878de26e3b9838c670519cf59329edbc9783690f13423e32924e31946c6b3968ca7988ce715329eabc978f691f15492f13421e33945c673928c671919cf7a329e16643cadc8782e27e3d94ec6d3808c6704194f6b329e5bc9785693f16c22e3b9968c672f19cf1e329e4bc9784e90f11c27e379818ce746329ead643c5790f13424e36947c6338a8c6725194f7f329e8d643cd793f1ec26e3d945c6731919cf31329ea3643ccf93f1dc4cc6b3858ce72a329ec6643c65643ccbc9780692f1bc44c6d39c8ce757643c3bc8788ac8788e90f11c26e3c923e0490047009afcbf0168f2beee59d0e4bdde33a0c93bbf3b419377821783b6d0a2e55bf884e113d0e45d918f4193fb0f8b409367f47e099a1ca7257f35bfa0c585fcf9967236b0f02fb294f363cbb2b8bd65997410eff6c6bcd281fddb1c7906e317cd73988ce708194f1119cf0e329e5f91f13427e379898c672019cf72329e32329ec6643c5791f16c21e3b9998ce779329ea3643cc7c8782e23e3d945c6b39b8ce77a329e8d643cfdc9785692f18c22e36947c6d3908ce70a329ead643c3792f1bc40c6739c8ce70419cfa5643c7bc878f692f15c4bc6b3898c673519cfad643cadc9784690f13420e3d94ec67339194f2b329e16643cebc9789691f19c24e33945c6d3848ca7928c671f19cfd5643caf90f11493f1ac25e31946c65348c6d38c8c670319cfed643c67c9785690f1dc41c6f336194f23329efd643c07c878ae24e379958ce726329e75643c43c878da92f124c8785e26e3b98e8ce74e329edbc8785691f1bc45c6b3938ce70c194f1b329e02329e83643c87c8789a92f16c23e3f9948ce706329e17c9780691f12c25e32927e3694fc6730919cf35643c9bc9786e21e35943c6936fe139eb8847fab265dd327ff64b9ef77123efe31749de478dbc8f5e24791f36f23e7c91e47dd0c8fbe04592f77e23effd1749de9546de951749de7b8cbcf75c2479ef32f2de7591e4cd7cdea2be47d15fc74fe9df04fc1fbfe379c611e3598351e6cf00a368380e477f473c51e73cfd09f2565e0cd47179d72601ff1f088caeea547f8351e66d750abf8b3dd0114fd4b9da4082bc951772cf48de0d4fc0ff0701a3ab3a35d06094795b9d3a0a3c831cf1449d630e22c85b79217de4f2eda004fc1fc7857555a706198c326fab53f81db4218e78a2ce8d8710e4adbc90673aa5ef2301ff1f068caeead4108351e66d75ea20f00c73c413754e3f8c206fe585bc1325cf5625e0ff38ce8dab3a35cc6094795b9dda0f3c231cf1541a3c95162fbea8bc9517f24d817dfa3701ffc7efe0bbaa53230c4699b7d5a94ae019e58827ea1a6a1441deca8b321d97777b13f0ff32607455a746198c326fab5338ce4d99239ea86bbf3282bc9517d26726dfa249c0ffcb81d1559d2a331865de56a7f0bbfce58e78a2ae59cbeb20efa8ebafbac83bea5aa22ef28e3a2fae8bbca3cef1ea22efa8f395bac8bbd2c8bbb20ef38e3a8ed445de516da2dfbffdfe1d77de5fe4b1a4d2c8bbb20ef3fe22f7ef2fb24dfd22db167fdee2dbb5bacadb9fb7709fb7fc25bebc93787dda24c6f5e27d811dfa17efed6c074deeb56c034dee976d054dee79be0a9adcb7de029af43dbc029af41fbd0d9af40162dfa4bcb371123479260dfbc4648c89e3a0c95814d817f30b1d3f0ada021dc73e80f93a7e18b49feb38de7bfe998e1f046d9e8e1f00ed231ddf0fda5c1ddf07da873a5e095a858ee33d9e393abe07b40f741cef2dbcafe3bb409bade36f81f69e8e7f0ada2c1d2f07eda7166da68e6f066d868e6f02ed273afe32683fd6f18da04dd7f10da0fd48c75f026d9a8eaf07ed873afe22685375fc05d0a6e8f83ad0ded5f1e741fb818eaf056db28eaf01edfb3abe1ab4493abe0ab4efe9f84ad026eaf80ad026e8f872d0beabe3cb40fb8e8e2f056d9c8eff0ab46feb781968f93a3e0ab4063a3e0234790f671868f26dd521a0c9fbe58340936fd00f04ad898ef7074d9e95c6316ae47b8e38468dbcb38963d4c877af178126dfdac0b167643c0e1ca346be01f60bd0e43d9605a0c9b75be78376a58eff1c34f9c6fdcf4093efd8cc034d9ec5fe0834f91ee25cd0e41dcc0f4193ef46578026dff298035a731dff0034f9a6d7fba0c97b20b341936fb1be079abc6f3d0b34f966fd4f412bd6f199a0dda2e33340bb55c77f02da6d3afe63d05aeaf874d0e4db1c3f024dbeff300d34f9a6da0f416bade3534193774ba78026efc3bd0b5a5b1dff0168f2dde3c9a0c9bb08df07ad838e4f02ada38e7f0fb4a48e4f04ad44c7278096d2f1ef82d649c7bf035aa98e8f03adb38e7f5bffaafd4fed97afebf97410dff994caef5c70fe9467cca7212e0cc813e7395611f0605eafc55ef654529553daaf7cbd5ea92faf41dea762cf3b99c9fbb45e57815eef2923ef0248f33fafafda3627b4d6402f77c6580eaf8165ddb24c3bd04f1aeb6eaacb7bda51794f194cc28d3e489a7fd74cea58b64737a08e9e7d4ba97d40ea5a001ee29486b830b8f12a95c4f3ed9af09c069ef8f7936489ab3a81fb569c6d88ed1e9059d78a20cd29f0efa403ff705f9775cbbce4e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1487f02f68f4bbad7491845c3beaed3f1f324b1cf55d6affa755e847e1dd7fd7b0df57adb1b652e8034ef37ab4abb51c70be1ffb2dda2b6a5837ec26ab7a5e45708e5390d3c2efa8bf3202f59f76b162f245e1c5bdea972371ea792ea3913d5c76e3ee3f6bac55357fb2bf6dda2a7b8bf9e3378b06fb41078dfd0bf0958cf1b500607fb78b5f542f2c37de935d0247e0e185d6c673c96487bd04ecf63dfb4a439aabd957ef1f8b77d2ae9b2dd3801654a0717d6ef0248730adabed7741c9f0d791d7c7bc7f27f99aaeba716ff54998fc55fe6243e032fdbf79825ef23c01a53dee73d7f9fa783e4237a01c4bfd9ac2aada4133fc46b6157fb883c3b8bece672e78ce58a20cd714bf9d341bce53f66f01c3398d536390bf5ec1d38febb6a938e4778d40e3c9234781ee4ead879c6e0110ec90fdbd146461a59b600d2bc0b6d942a8bb4f352cea86380ebe398acdb761c338f0b094b1955fd98714515efc5fefcd727d05ec4fdfcd7275087f039adc0587f7b58bf70350aa28f2d92e637c671d4c535066e4bd34ff459d2fc1edaa16bf4c3b8b99ceb7f51d76d51e7fac71df02482f3afbdd554ddf11d8f31271cf0382a67d276ec3a6994a908d2b484723a388fa9f63dc26390b78b6d8e5ec839d429c38b0248f3df8cb623ca47bc563d5d27654959cf07db5bca2269fed568a78e3a6072b9dd8e4099d47a5fb39455d2fc3bb47fff17cee7653be171f8b2e617fe5fa6eada03f14f95f950fc654ee2bb9fb27d0f59f23e00ac31e57dde7ba772be2ff9885e00f144f3aab4924efc10af855ded23f26e1bb29bcb9d32962b8234872de54f07f196ff90c173c860cebc87d4bc2a2ef5c865bb7938c2a3f6e091a4c1fbc7726cc7f71b6df7b55c7d7b35eabc19bfbd2a1ab6cfd780a72e9efdb65db398f7506de783ed0d7e3c1f6cae999b06e7bf8f836dce8b6e9ff92fc1f75c03284760943530d81cf95c8a3e9bf700db826efa2cffb35d33b4049febe2feb4709bd702783d22dce67106af47ee046e55ef653be17d44d1ded4bf8ecec94bf17a4b8e31e63939de47eb08ecb8ac70bd61298b782069f3e1fff2bfbf04f6eb93cf5ace8c9f359651febe69a4b3e5d304968ded5d8d9264d2e43f637062db2ce96cbeca7e80754ed665ee2b785f54d2f436da2433addaf6139b56f923db51bcc3f604eba4abfb4851dfea96fc14a3dc03c2ef9bbbb88f92ebfb53786fc545dbeea88d4ee2bd8bf8beffd07d8ced9ecbeb865745c185f7335cb6e951e723a72c79c7e7456aacadbfdfe6455df6f77fd63dcd26463c9ebcbb94dbda399b17272c3c2eeebf54e7c5094bde317a31de764fc4e6c5710b8fabebed282f8e5bf28ecf8baed6fb55362f8e59785c5d77457921f9e5ca7c8280b989118f27efd231785faa3a2f8e5a78e2bf2755bd17472d79c7e7454997eafa3fd18b23161e57fd98515e1cb1e41d9f17ddbadbee5fd8bc386ce1395cc75e1cb6e41d63bd1867bbbf64f3e29085c7c1bdc66abd3864c93bc6f3c32e78afb13a2f0e5a780ed6b117072d79c7e84599ed3ea8cd8b03161e57f741a3bc3860c93b3e2fc6745679efaf8117fb2d3cfbebd88bfd96bce3f3a2ac9bca7b5f0dbcd867e1d957c75eecb3e41de33554a65e54d6c08b4a0b4f651d7b5169c93b3e2fc666ceb5f6d6c08bbd169ebd75ecc55e4bdef17991cc1c53f7d4c08b3d169e3d75ecc51e4bde31d68bccf5e4ee1a78b1dbc2b3bb8ebdd86dc93bc6e348a65eecaa8117bb2c3cbbead88b5d96bce3f3627ce6fed3ce1a78b1d3c2b3b38ebdd869c93bc67b2e997ab1a3065eecb0f0eca8632f7658f28ecf8b4e9963eaf61a78b1ddc2b3bd8ebdd86ec93b3e2fc665fac4b6d5c08b6d169e6d75ecc5364bde319e7766da8bad35f062ab85676b1d7bb1d592778ce79d99fb17afd6c08b572d3cafd6b117af5af28eb1edcc9c776ea981175b2c3c5bead88b2d96bc633cefcc78f14a0dbc78c5c2f34a1d7bf18a25ef18cf3b33c791cd35f062b38567731d7bb1d992778cf522d3766eaa81179b2c3c9bead88b4d96bc63bcaf95693b5fae81172f5b785eae632f5eb6e41de3f548e61edfc61a78b1d1c2b3b18ebdd868c93bc6bea2cc39f8861a78b1c1c2b3a18ebdd80079bb7a5f47f29067b1da185e14409aff6c3c8b15e5a3ac039f2bc3b2bc147b59b2cf95ad8f28cb4b501649f33f8c67f9d63b607254d64c9d7911caa4d67bce525649f3bfe099e17f8367cf659bbc01be5dd2e2c2ffcb54dd3348e29f2af3baf8cb9ca9abcf03671af2c1bcd7026b4c799760def26cbae4237a01c49bb4a84a2be9c40ff15ad8d53ef2828e23bbb9dc0663b92248f382a5fce920def2af3378d619cc99f71ea09e493d72d37665995e88f0a80d782469f099bd371cf19c33788443f2c3e70c1b196964d902487385f6509edb95e720a59c51cf483a68cbaa7d4652f2c3678b5f0346b38caa7ef483673f3b6abd4350a5950837aca7d4d054593b3b2aabe425eb96f9cec028635294d63d63aaa68c9d0c46c5d3d5816738ce864cd51d2fba024f17073c8eca99390e7533cad4d9285311a4c1771bbb3928671ee42beb96f96e90b78b6d8e5ec831f90ec38b0248d311dab3ea7c9475a8fa5b6a294b4fc76591754bbbd4b30ef2ee6ee49d32f24e04e76fe720a87effea0ecc3d1c30abf5f68a7fbd99fdeb2ebd2ea953924f0acad41b3c88ab4c98b79ce7493ea21740fc5e38cf9374e2871cbf845dd565d996c86e2ed7d558ae08d2f4b4943f1dc45bfe5e064f2f83596d93ee706ee7607fc8d4819e0687cca7c0bb5e11def504ef240d1eff4a1d79d7c3e0e961e4ad78e41ca71b6872ae20fc09f87fb20eb8cd76af9b855bb4eec0683bd7e9143f63b5e73a9d8051b41ec0d3dd9167e6b6bec3f0078fcb8d8c34b26c01a41902c7c68425addaeffe19ca256317c638ce4fa64d6fe4c02f1c5731007f02c3c300fc92723674c073695035b6e29c8a19b3cb268ceb3f2edbf52868050626fee6598a910f1ac61b58b420387f08c902d06408c986a0e51bb6e0d095925e86b4736117fa21eb2e30389b004b9c79e3f09b325557751a038f8baaacaace657a5dbaea0c9a3da9621cd68f8606676dea8efa5f836ad245adcbd57630f78934cc9b75b0c051fe0da0bc699897fcd4b629d4f19965e553face9e3077dab8e91573d02873c7c6785e70fe06307fa30c77b5d36105c00263e3d0d028173618f23fd93097c6cf598a63dc9ade04909f4c97826f9738f04dad5fc6aa2d2f9b3ab5dfdc31532795df3f777a79c5a419d3716b36319c8bdad2f2ff46a0d99a784cab266cb670d9c616cd36e1a8c04d409323d725a009cfa5a03580b8a437b78c93eada12d62fbb94fa9f32a7a12e78e3a0aa0ac8e158b5ab6aff55a7729707d953a12b82ece654430daba185d550c26ae8603554b01ad1527dd542dd7556674f6a685f3594af1aba570dd55b1c6487e2bd35a81a6a574def02e7ed41f6544b0d9ddb3ac80e8dab6e57aad7d5d5a7ddd4a734d429bbba15a04e73d5659dba0451a79dea7453ddb250b7afd4699c3a4556a77fea944d5d82a84b0f75a9a82e9dfa68affb86e1ee30dc13867bc3705f18ee0fc3036178300c0f85e1e1303c128647c3f058181e0fc31361e817862783ec50d203c2f054901d6afae9203b0cf5e0203b44f5d0203b7cf5f0203bb4f5c8203becf5e8203b24f698203ba4f9d8203b4ceef8203bd4eec4203b5cefe4203b34f0d4203bbcf0f4203b94f1cc203b1cb21a3a590dbdac866456c337aba19ed550d16a08e9854176686a35ecf4e2302c09c3b361782ec80edbbd2cc80ef3ad86ff5e1964870b57c388abe1c5555782ea42515d0beab6bdeabe52b796559796bae5adba6255d7b4eaaa578f2ea84739d4a32dea511ff5e8937a144c3d1aa71e15548f4eaa4749d5a3b5ea5163f5e87565907d347f7f907d7543bdcaa25eed51af3aa957bf8e06d95703d5eb9dea7549f5faaf7a1dfa7490bd9dad5ead575d9cea16b7ba95ad6eebabdbee6a68f9b7c3f095307c350c5f0bc3d7c3f08d307c330cef84e15b4176f8e1ef04d9218cd510c8df0fb2432babfaa8866cfe51901d0afa27417688e9f782ecd0d51f04d921b13f0ab2436dab21b8d510debf0cc3c74176d86f35fcf9af83ec90f6bf09c36fc3f05761f85d187e1f86bf0ec31fc2f0c730fc4d18fe360c7f1786bf0fc33f84e11fc3f04f61f8535035f4353616bfd333b7e8f9b28a8a71d366561457cc289e36776ac5a499531716cf9f5431b178c6bc71b3c74f9d311f175eaf9b2719b7bbefecd9650b8b274d1f3b6e41f18cb915c533c6178f993177fad8f30ed427f442375c9863d9d8b1d1997d3dff73907eab9699bea7979311d11faabe6c1fd6c6908f6bb3d0ffae658166eaa397dc3e19903dd72d9e3375464571b2787af8373cb8ce983f6e6c8762fcdf9cd0e43915c5732aca6657148f9f3d635a7149075cef078d6b51883f35760353704dedccf9573d9672adaad89166b570e007cd6a47fa71b3cf41fa692d33fdafb529e1bfd466a166cd6b47785bf3485be6cc1d5331bbacbc227ae1d69f67e10ecd6b51ccbb6a59cc3fd726b3ff5e9b859ab6a81d618716b5c86c700e9905ff0f4017f891c0fa0400", + "bytecode": "0x1f8b08000000000000ffed9d09941545bee6b38a62d16b95b82bb8948a82acb72ec58e50b8e0ae08222020140508c84eb183b28328822cb243b1ef8be0d26def76b7bda96d2f6adbfdba5f77bff7fabd7ef3ce9cf3e6cc3b33f366c69e8c7be33ff511449675cb8cf2bb12794ed48dfc2a32e3175f46462e9199911764a6bf86214fc71b84a14570fe24ff2fd3bfc92f3695c4b8aea44bcebc1ce1cccf11ce0639c25990239c0d7384b3518e7036ce11ce2639c279518e705e9c239c891ce1bc2447380b7384b32847382fcd11cea639c279598e705e9e239c57e408e79539c279558e705e9d239cd7e408e7b539c2795d8e7036cb11cee639c2797d8e70de90239c37e608e74d39c2599c239c37e708e72d39c2796b8c9c6d8053eed9dfa67f6fd7bf2df56f2bfd7b87fe6dad7fdbe83216e8f9b661681786f661e860fc4f19a36edca7c2d0d1f85f69183a85a17318bae8ff15ebff750d43b730740f438f30f40cc39d61e81586deda8f3e61b82b0c7787e19e30dc1b86be61b82f0cf787e181303c188687c2f070181e09c3a361782c0cfdc2f07818fa876140189e08c3c0303c19864106cbe0300c09c35361181a866161181e86a7c330220c23c3501e865161a808c3e8308c09c3d8303c13867161181f86096178360c13c330290c93c330250c53c3302d0cd3c330230c95619819865961986d7836270c73c3302f0cf30dce0561581886e7c2f07c1816856171189684616918968561791856846165185685e18530ac0ec38b6178290c6bc2f07218d686615d185e09c3fa306c08c3c6306c0ac3ab61d81c862d61d81a866d61d8ae596447d811869d61d81586dd61a80ac39e30ec0dc3be30ec0fc381301c0cc3a1301c0ec391301c0dc3b1301c0fc389309c0cc3a9309c0ec36b61381386b361783d0c6f84e1cd30bc1586af85e1eb61783b0cdf08c337c3f0ad307c3b0cdf09c377c3f0bd30bc1386ef87e10761f86118de0dc38fc2f0e330fc240c3f0dc3cf0ccfdf0bc3fb61f8200c3fd7da87faf717faf797faf757faf7d7faf723fdfbb1fefd44fffe46ff7eaa7f7fab7f7fa77fff4efffe5efffe41fffebdfefda3fefd93fefdb3fefd07fdfb8ffaf79ff4ef5ff4ef3febdf7fd1bfaa1f6f75f34cbc49503d950531b539a563cad57d7c31d3ec27547d500df4ffe4b758eb057a5e7ef3b4de50cf3734f4467abe91b19e267abe89a117e9f922436faae79b1afae57afe7243bf52cf5f69e837ebf99b414fe8ff650a96f9515a032de58126f52f1fb4865a6b005a23591d688db5d61034d9be8d40bb486b8d41bb586b4d404b68ed22d02ed1dac5a0156a2d015a91d62e01ed52ad1582d6546b45a05da6b54b41bb5c6b4d41bb426b978176a5d62e07ed2aad5d01dad55abb12b46bb4761568d76aed6ad0aed3da35a035d3dab5a0e95d2cb80eb4ebb5d60cb41bb4d61cb41bb5763d683769ed06d08ab5762368376bed26d06ed15a3168b76aed66d05a68ed16d0e45ce156ada97a266d5f7a19ade783769becdfa0dd2efb36682d65bf06ad95ecd3a0dd01798bd65af671d0da684deab8fa5f671d2f0be26adf52156abd5de25e6fb866b5de6ef1af37a9dacbee41b5d765904f17f0aa878ec7f83c4309e69da783e4237a01c4ef83b4924efc90764ad855dbd355c77bd4b05c6763b92248d3d552feb220def2773378ba19cc6a9bf4048ef8eb6cc7a4afb3b59eb2aeb30321ad59f7e498f955acb30f0287833a5beaeb6cada7aceb6c05a435eb9e9cbf7d15ebec60e0705067bbbaa9b3a9a4afb3997b264160af7b722df155acb3638123fe3adbc9d7d9da4f59d7d9e721ad59f7e4baf6ab58672b8123fe3adba5ab3f37a8f594759d5d0369cdba27f758be8a7576097038a8b315be9dadf594759ddd0e69cdba27f7fbbe8a75761d70c45f67bb39aab31d7d9d0d32fd5f4160af7b72eff9ab5867770147fc75b6c2df9fadfd94759d7d0bd29a754ffa41be8a75f6b88eab7e860f753fc3f5a0fd426b3780f64baddd08daafb4761368bf86fe42d13e92be44d03ed6da2da07da2b55b41fb8dd1f7aab44fb5761b68bfd5daeda0fd4e6b2d41fb3badb502edf75abb03b43f68ad35687fafb536a0fd516b6d41fb93d6da81f667adb507ed1fb4d601b47fd45a12b47fd25a09687fd15a0ab47fd65a47d0fe456ba5a0fd556b9db4a6fa29a5efeb5dad3501aeb220be3a9a000f64ca33e6cb20dec12d4fb2087830af92f8f3eaa8ca7ecec3569f53f612e04939287b02f2a80d4f0a783ac6cf937ec7af34fef5a6b771d2f034017925a15c9d1c942b0ff29275cbbce457041aeed39d2c8cb19f6784175e799097ac5be63b03a368d8c6489b2bfb8f3ac6fc2bf03ad897d2e719929fbcbb2c1c25a04b9ae2e6d56cff556b85f07f6c6f3b1a9aa37a99ae179297ac5be64b8151cad3b1fe1953b5654c198caeda883cc84bd6edf3aede0e126f0f3c5d1df1986d9ae4ddb51ef2ee6ce45d62e48d6da74c351ddb3a03b383ebad922fe37a0bcf1f18aeb72ecbab4e6b5e37493b9cedf556276339c6ebad4679d51c0ef687741de86a70c87c0978d72dc2bbaee09da4b90dbc7370ee99f6ae8bc123f329e09176ac1478dad7334f7b82bcf11c56b61b5e4be17980abedd5de609479dbf6ea0c8c290ba38373c2544dc7c81260140def47251d7916b55d932479bbb8aec47729e4dcdcbcb6298034ff273ff3abdaca76794ed95278ee2c536daf79e3df4ea924ee1fb5e171bc0f9538aa8f49bc7ff359106f5d33db25b3bd89bac7e3aa2d4f1a3c322ff97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563cd29f80cf6d49ba8e248ce6f36faeeef3a7bf8522ebd2bfaa5fe7dbd0af137fbf452a897d7ff21c444ba3cc0590e6c3bceab4efe8b87ae640faa9f0592bf3f92b977d76f83c6619cc4b7ef8ac156e4b86e79d8a63cb3bf35d1a17fd6d9706996fea98cf7e76b478eae2f967f434cff0149f03bfc3e051f5f46ff9d56c2efafeb2ed8b44af241e67df5e5160afebf16f97d4397dd6f9c1b9ed071e675c3dbf236db5f4977735f22e80347f80e7a8e4d92a196728692c87cffdc8ba659996a07733d6dd542f2b1c0d8df597c2b292e64fd0a62e83baeaa0ad4c65fbec3af69bc77f1ccef4e327b3e0690f3c2eda1947e71b49dc07e2eec7379f4fb39dc7481a7cb6cfc17395353eef24f97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563c665f2bbe5f5b42c2289ae3671fd2fd19adf4ba64fdaa5f677a7e75beaefbe1a4cfa99551667c77f46c7e75da593a5e189cffbc43d4b674f57d8aa86d29f9e1b767da038f8b7edd3cc84bd6ddc1e285c48b63cb3bd38f1fbfc7d5fdf849c3d7128ba7aef657ec63454f717f4d193cd8371af56d9f0e86e6681fafb15e487eb82f75004de2f87eb48bed8cc712f3b91ec90ffbaf5fd6de360d5c6dfb54d265bb81df4d290bceafdff83d950dd0f66dd2717c86039f1dd96ff9bf4c35f5538b7faacc3de32f737afbde099c65900fe6dd0b5863cabb04f3ced341f211bd00e2fbf2abd34a3af143bc1676b58fc8376090dd5c2e652c5704697a58ca5f16c45bfe9e064f4f83596d932d50cff6c3f1df559bd423c2a396e091a4c1f32057cfe4996da4f97c233eb7d7c84883e72c92e638b451aa2cb6e7476dcf1cba3a8e453d73683b376e0f8c6619cde73c2ff4e7b4be09ed45dccf697d13ea103ea71518eb6f05eb17ae4641f4b145d27cd758bf794e2ecbe0736092e6fbd05efc471dcec9bfaceb2bdb39392e175576c58cdf412b8b9119eb04b2e07982a479dfd866dd22b83b5b96fd306259f1cafc56586170be7f6ebeb396d9e77b1a65917add03ca22693e36ce01e33f6fc99c03bafaa61c9e7ba8f576b09455d2fc0ef6b5dfc3399e6c27dc6fffcdf27f996a3a07c4f11c7bc75fe624ee33b27d7b5bf2ee03ac31e55d82eb9273c03e86070510ff2fd0a64b3a492b5e0bbbda47e43c0ad9cde5ba1acb15419a5e96f29705f196bfb7c1d3db6056dbe48f50cffe0dce015db5d5bd223c6a051e491abca768fb0ea8ed18e3ead9fea8634c076034db4d3c4eba6433df1332efabd9ce11248d2c8be708ff09ed6cc292d6bc5f28c7cb389f1bc677254a21dfbf59f22d8bd9cf2ee05b19cce379c19799b783ef84a7df11c1ef0a0a034e6510c76f87cb72f9c0e8e27beb89e0dcef037f1e237e835d966b008c2eb661b6df272e054659ae00185dbcff85dfc8af0d634760c47d51185d7c97b4aedf73c4ebee46c0c8f45e15de3f6e0c8c2eee73d4f57d1a3ce636815f57638724b360c463ae2c771130bab87f85f7ef6bc388e72eb2dcc5c0e8e23e73b663b0e0f7a1f1fe8f30ba3807ccf61a05ef55c97297006377478cddb260ec0e8c78cf41185d5c4f2620dfda30f60046e41546077d0069c61e5930e2bd7259ee5260bcd31163cf2c18ef044659ae2930bab89f9f807c6bc3d80b1865b9cb80d1c1b57e9ab157168c784d2ccb5d0e8c658e187b67c158068cb2dc15c0e8e2ba3d61307c1e631f6014fd4a60bccb11639f2c18ef024659ee2a60bcdb11e35d5930de0d8cb2dcd5c0788f23c6bbb360bc071865b96b80f15e478cf764c1782f30ca72d702635f478cf766c1d8171865b9eb80f13e478c7db360bc0f1865b966c078bf23c6fbb260bc1f1865b9e6c0f88023c6fbb3607c001865b9eb81f141478c0f64c1f82030ca723700e3438e181fcc82f1216094e56e04c6871d313e9405e3c3c028cbdd048c8f38627c380bc6478051962b06c6471d313e9205e3a3c028cbdd0c8c8f39627c340bc6c7805196bb0518fb39627c2c0bc67ec028cbdd0a8c8f3b62ec9705e3e3c0d8cfc2d8df11e3e35930f6074659ee0e601c103f63fa3b34fdb3601c003c4fc4cf93f66c40163c4fb8e5497fc3698025af27e3cf2bbd2d0606b52ffb93c033287e9ef4b678320b1e612882e5d0b3c1f133a63d1b9405e360e019123f4fdab3c159f00c01cf065b3c7b2a7ec6b46743b2607c0a7886c6cf93f6eca92c788682674f593c1b163f63dab3a159300e039ee1f1f3a43d1b9605cf70f06c98c5b3a7e3674c7b363c0bc6a7816744fc3c69cf9ece82670478f6b4c5b391f133a63d1b9105e348e0298f9f27edd9c82c78cac1b39116cf46c5cf98f6ac3c0bc651c053113f4fdab35159f0548067a32c9e8d8e9f31ed5945168ca381674cfc3c69cf4667c133063c1b6df16cac23c63159308eb5f0c4fd7dd13196bcc6392afb3341edcb2e0c45b01c328e77c4382e0bc6f1c028cb61fffa04478ce3b3609c008cb21cf6af3feb887142168ccf02a32c87fdeb131d313e9b05e3446094e5b07f7d9223c68959304e0246590efbd7273b629c9405e36460445e619ce2887172168c53804b96c3fef5a98e18a764c13815186539ec5f9fe688716a168cd3805196c3fef5e98e18a765c1381d186539ec5f9fe188717a168c33805196c3fef54a478c33b260ac0446590efbd7673a62accc82712630ca72d8bf3ecb11e3cc2c186701a32c87fdebb31d31ceca82713630ca72d8bf3ec711e3ec2c18e700a32c87fdeb731d31cec982712e30ca72d8bf3ecf11e3dc2c18e701a32c87fdebf31d31cecb82713e30ca72d8bfbec011e3fc2c181700a32c87fdeb0b1d312ec882712130ca7278cdf59c23c68559303e078c0b3de305c1883cc5f1f124b1ec98d7f304657fdec29317b8293be6b588a0ec8bf46fae313e97038c637380d1fbe8193de3578fd1efd7de472646efa3f7d1337a46cfe8192f74c65c68c33d634ed4c7545d1915cfe2f879d29e2dca8267317826cb3d91038ccfe700e3736e19537565543c4be2e7497bb6380b9e25e0992cf7845bc6545d1915cfd2f879d29e2dc982672978b6c4e29903c6545d1915cfb2f879d29e2dcd82671978b6d4e29903c6545d1915cff2f879d29e2dcb82673978b6cce29903c6545d1915cf8af879d29e2dcf82670578b6dce29903c6545d1915cfcaf879d29eadc882672578b6c2e29903c6545d1915cfaaf879d29eadcc82671578b6d2e29903c6545d1915cf0bf1f3a43d5b9505cf0be0d92a8b67ac8c637380f1b91c60cc051f3da3676462f4fbb5f79189d1fbe87df48c9ed133e62ee3f339c0e8b7b56764655c1d3f632a5bc6d58e3d7354cef4385e2fea75c5f86d8994f2ea25c3ab5586574590e645f0ef2507fee541beb26e9997fcb2656e41c0ec28ef948c2fbdcac8ef39c30f35add1bf0d411f0b9ebeace332869fa47f1e744933570f98226383caf42c94774dfce52da969df96fc90673419cf22329ea7c9789692f10c26e35941c6f33819cf43643cf792f1f426e36943c633878ca72519cf74329e14194f03329eb6643cddc8784690f18c21e31942c633918ca73f19cfc3643cadc878fa92f19491f17427e3994bc65342c633838ca70b19cf24329e67c8781693f18c24e35948c6f31419cf32329e01643c2bc9781e21e3b98f8ca70719cf3c329e24194f25194f67329e3e643ce3c8782693f19493f10c25e31948c6f328194f0b329efbc978ee22e3e949c6339f8ca70319cf4c329e4e643c53c878c693f12c21e31945c6b39c8c671819cfed643c4f92f13c46c6731b19cf03643c7793f1dc49c6b3808ca71d19cf2c329e52329ef6643c13c878a692f15490f10c27e31944c6d38f8ce741329ed5643cf790f1f422e3e94ac6339b8ca73519cf34329e8e643c79043c89e0fc775213f0ffd5a0e51bcb360e4345f3eaffafd57a3e2cb34ec71b58d6bd16b497757c9d6559f4692d94a54cc7935f6c4afb847995c1bce457081ceb48783a92f14c23e3694dc6339b8ca72b194f2f329e7bc8785693f13c48c6d38f8c671019cf70329e0a329ea9643c13c878da93f19492f1cc22e36947c6b3808ce74e329ebbc9781e20e3b98d8ce731329e27c9786e27e31946c6b39c8c671419cf12329ef1643c53c8783a91f1cc24e3e940c6339f8ca72719cf5d643cf793f1b420e379948c672019cf50329e72329ec9643ce3c878fa90f17426e3a924e34992f1cc23e3e941c6731f19cf23643c2bc9780690f12c23e3798a8c672119cf48329ec5643ccf90f14c22e3e942c633838ca7848c672e194f77329e32329ebe643cadc8781e26e3e94fc633918c670819cf18329e11643cddc878da92f13420e34991f14c27e36949c633878ca70d194f6f329e7bc9781e22e3799c8c670519cf60329ea5643c4f93f12c22e3194dc6f3ac85c7c1f88e691e793f4fd62df3ab49f276b01dd2e35abee2a84cebf5ba1aeaf50abfe45700693e699cf96d1a64ea83e8c2b546c7b16e8837ebc1a3f58eca22db23cfd83e8ef34ee17ba3013004863f8185c7c5fbb68eca794e3d8c7b7cd50d8657e6b62b8234af807f1b1cf867abdb322ff965cbdc828019eb4571106fbdd8187f99feffb8ade2eb46c35f2cd7ab3a1e63bd4caa756cd2eb6a08f9bd0af96ed1f1bc18f355ebdaacd725e3cc0ac716d025cd7f83761999d524ed2f7e636dab8e97c5c79c1e071bc7d1154f702a83f856e0d9ec80c75139d3db669b51a6d546998a20cd2628e73607e5cc837c65dd32bf0d7864c2b1875dd483da6cf3a8b18719781691f13c4dc6b3948c673019cf0a329ec7c9781e22e3b9978ca737194f1b329e39643c2dc978a693f1a4c8781a90f1b425e3e946c633828c670c19cf10329e89643cfdc9783691f13c4cc6d38a8ca72f194f19194f77329eb9643c25643c33c878ba90f14c22e379868c673119cf48329e85643c4f91f12c23e31940c6b3928ce711329efbc8787a90f1cc23e34992f15492f17426e3e943c6338e8c6732194f3919cf50329e81643c8f92f1b420e3b99f8ce72e329e9e643cf3c9783a90f1cc24e3e944c633858c673c19cf12329e51643ccbc9788691f1dc4ec6f32419cf63643c1bc8781e20e3b99b8ce74e329e05643cedc8786691f19492f1b427e39940c633958ca7828c673819cf20329e7e643c0f92f1dc43c6d38b8ca72b19cf6c329ed6643cd3c8783a92f1e411f0448d3d2cffdf009abc5387e3116fd7f1cda0e55bf29067cfb78156a0e3b20ef52ae7e4e6e7af1b7d72f51e21e65506f3921f8e3dbc9d84a72319cf34329ed6643cb3c978ba92f1f422e3b9878ce741329e7e643c83c8788693f15490f14c25e39940c6d39e8ca7948c6716194f3b329e05643c7792f1dc4dc6f30019cf06329ec7c8789e24e3b99d8c671819cf72329e51643c4bc878c693f14c21e3e944c633938ca70319cf7c329e9e643c7791f1dc4fc6d3828ce751329e81643c43c978cac9782693f18c23e3e943c6d3998ca7928c2749c6338f8ca70719cf7d643c8f90f1ac24e31940c6b38c8ce729329e85643c23c9781693f13c43c633898ca70b19cf0c329e12329eb9643cddc978cac878fa92f1b422e379988c6713194f7f329e89643c43c878c690f18c20e3e946c6d3968ca701194f8a8c673a194f4b329e39643c6dc8787a93f1dc4bc6f31019cfe3643c2bc8780693f12c25e3799a8c671119cf68329e67eb87a754bd8b87e37d0a174e6510df063c9b1cf8e3a89c497c0f33ceb13495573b0caf36185e15419aade0df0e07fee541beb26e9997fc3cb3678e62563cd2b7637b3f782109a3689b9cf29426135066996a6a1f77008f8be38723dfd3edd84ea34c0b2dbe4b1aacab3b1d94d3b6efc8fc4e4bdec541bc5eecaa8517bb2c3cbbead90bc92f5be6ad39c8ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccdee7fa61f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf7563563c8b745c5813906e1109a368dbdcf2a4df375a149c3be519f36510df053c3b1cf8e3a89ce967c8771b655a149cefbba4c1fd6bb78372daf61d99df0ddb211be69d39c8ec7dae1bb3e259ace38bf46f02d22d2661146d875b9e743bb6383877aaa91ddb0d3c2eda7947e54cb763554699165b7c9734b87f553928a76ddf91f92ad80e559ed9335b9815cf121d17d604a45b42c228da2ea73ca9f4fb8d4b8273a79adab12ae071d1ce3bf23ddd8eed31cab4c4e2bba4c1babac741396dfb8ecc4b7ed932efcc4166efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fb7ce1f8ac78e49bc0c29a80744b491845dbed94a763badf616970ee9467cc97417c0ff054c5ce93e97770e07bbadf61af51a6a516df250dee5f7b1d94d3b6efc8fc5ed80e5f75e69d39c8eceb46fd30fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5cc503714cf321d17d604a45b46c2285a955b9ef4770f9605e74e79c67c19c4f702cf1e07fe382a67fab99d7d469996597c9734b87fed73504edbbe23f3fb603b7866cf6c63563ccb755c5813906e3909a3687bdcf2a4dbb1e5c1b9534dedd83ee071d1ce3b2a67ba1ddb6f9469b9c57749837575bf8372daf61d99df0fdbc1337b661bb3e259a1e3c29a80742b481845dbeb9627dd8ead08ce9d6a6ac7f6038f8b76de5139d3edd801a34c2b2cbe4b1aacab071c94d3b6efc8fc01d80e9ed933db9815cf4a1d17d604a45b49c228da3eb73ce9766c6570ee54533b7600785cb4f38eca996ec70e1a655a69f15dd2605d3de8a09cb67d47e60fc276f0cc9ed9c6ac78faebb8b026205d7f1246d1f0fce750fc3ca50983474d35b563871cfbe3a89ce976ec7060f7fd10f82e69b0ae1e7650ce3cc857d62df387613b64c3bc330799bdcf7563563c03755c5813906e2009a3680781e748fc3ca50983474d35b563471cfbe3a89ce976ec6860f7fd08f82e6970ff3aeaa09c7990afac5be68fc276c88679670e327b9febc6ac7806e9b8b02620dd201246d10e03cfb1d87932df37461e35d5d48e1d73ec8f9b7266dab1e381ddf763e0bba4c1fdebb88372e641beb26e993f0edbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a2e3c29a8074434818453b0a3c2762e7c9f43b208f9a6aea7738e1d81f37e5ccf43b9c0cecbe9f00df250dd6d5930eca9907f9caba65fe246c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a67a88e0b6b02d20d256114ed38f09c8a9fa73461f0a8a9a67e87538efd7154ce74bfc3e9c0eefb29f05dd2605d3deda09c7990afac5be64fc376f0cc9ed9c6ac7886ebb8b02620dd701246d14e02cf6bb1f364fa4f91474d35b563af39f6c74d3933edd899c0eefb6be0bba4c1ba7ac64139f3205f59b7cc9f81ed900df3ce1c64f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf178ecf8a67848e0b6b02d28d206114ed34f09c8d9da7633261f0a8a9a67e87b38efd7153ce4cbfc3eb81ddf7b3e0bba4c1fdeb7507e5cc837c65dd32ff3a6c87af3af3ce1c64f675a37e987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e6266a81b8aa75cc7853501e9ca4918453b033c6fc4cf539a3078d454d3733b6f38f6c75139d3cfedbc19d87d7f037c9734b87fbde9a09c7990afac5be6df84ede0993db38d59f154e8b8b026205d0509a368afbbe549250c1e35d5d48ebd093c5f8b9f27ddaebe9905cfd780e7adf8794a1c9533a9d6fb75608f6bbdcaabb70dafde34bc2a8234c8f0b603fff2205f59b7cc4b7e9ed9334731635b28ac0948f70609a3686f018f8b764395bdb55e97acbf61180637adcef76cfcf996e2354b43bd5ee190fc0a20cdfdcdaad30ed36c85f07fd96eaa3c670ccdd1b76f4a6cef4bc8bce45718d4db35448dd734e8858be7fcb33deea31712ff2c88af5ee37e8e79b9f8b652b6ef5c9cb6f0c458f692a8f74d5c7cc74e95bd8d5e97ac5feda3539b3af5bc14f73d693fda18652e80342da0fda884f6c3d656b8de37f302fbbe991f54b767c255ac75f3dec4675a977467213db639fdf52fee9ffda1acaedac5a86b126c17cdb6dba5f7e6fd3133ef22f0e52ca967b6eb38f471a0857b200137d6c7fadccf64ddb67b08030d1fd93cc36d7dd6e2e3200bf720026ec6fd7a90e1239b679fb75f0fb1700f21e066dcaf87183eb279f679fbf5500bf750026ec6fd7aa8e1239b679fb75f0fb7700f27e066dcaf871b3eb279f679fbf5080bf708026ec6fd7a84e1239b679fb75f975bb8cb09b819f7eb72c34736cf3e6fbfaeb07057107033eed7b5ed2765daaf1dddff4ef793a2676aaae99ee159a7fe64be579fcdf327af018f8b3ae5a81e241ddd734df7939ae30f9c35bcc2f1071cdf97adf1bb44929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e667cbf17fb5724ddeb248ca2397e363fdd9fd156af4bd6af9efd9d7d99cb7c5349ecf794e7924d8e0248f3efd756a79dafd9b07f11fb454f1b9acb6d698e3f2df3925f219407ebbfab77b5a3ead6eb96bc8b63cb3b55e1c6e354f2d2701d1705d5dbf994511ef4f464ecf99feb699ee1e949c77967fbbe04f238e88b2d7154ce745b70c22893e97111a46901e53ce1a09c7990afac5be64f008f4cf9c0e3aa0e06064f60f147a6d1643c83c9781e22e3b9998ca73719cf55643c73c87852643c6dc8782e22e39948c633828ca73f194f5f329eebc978ba93f13425e39941c6d3858ca7808ce719329ea7c8781e21e3b9958ca70f19cf1d643cd790f1cc23e34992f124c8782693f19493f10c24e3b99f8ce746329e9e643c9793f1cc24e3e944c6d3888c673c19cf30329edbc9781e23e3b98d8ce76e329eebc8781690f1b427e32924e3994ac65341c633888ce741329e62329e5e643c5792f1cc26e3e948c6d3848ce759329ea7c9781e27e3b9978ca739194f37329e96643c9792f14c27e36940c633868ca72d19cf10329e87c9785a91f1dc42c65346c6733519cf5c329e12329efa7827201b9e8bc9782691f18c24e31940c6731f19cf0d643c3dc8782e23e3a924e3e94cc6d3908c671c19cf50329e47c9785a90f1dc45c6732d19cf7c329e0e643c9790f14c21e31945c673868ce749329e07c8786e22e3b9938ce70a329e59643ca5643c8dc9782690f1b423e3194ec6d38f8ce71e329e66643c5dc9788ac878a691f1b426e3c923e04904e77f4b2701ff7f0d34f9e60b7e2f2cdfb23ee9a796f4eab838a7f9f9ebceb7acfba485017d3a0e6529d3f1e4179bcef9ce4d9e5eafcc4b7e85c0719284a73519cf34329e22329eae643ccdc878ee21e3e947c6339c8ca71d19cf04329ec6643ca5643cb3c878ae20e3b9938ce726329e07c8789e24e33943c6338a8c670a19cf25643c1dc878e693f15c4bc67317194f0b329e47c9788692f18c23e36948c6d3998ca7928ce732329e1e643c3790f1dc47c633808c672419cf24329e8bc9784e93f19490f1cc25e3b99a8ca78c8ce716329e56643c0f93f10c21e3694bc633868ca70119cf74329e4bc9785a92f17423e3694ec6732f19cfe3643c4f93f13c4bc6d3848ca72319cf6c329e2bc9787a91f11493f13c48c633888ca7828c672a194f21194f7b329e05643cd791f1dc4dc6731b19cf63643cb793f10c23e3194fc6d3888ca71319cf4c329ecbc9787a92f1dc48c6733f19cf40329e72329ec9643c09329e2419cf3c329e6bc878ee20e3e943c6732b19cf23643c4f91f13c43c65340c6d3858c6706194f53329eee643cd793f1f425e3e94fc633828c672219cf45643c6dc87852643c73c878ae22e3e94dc6733319cf43643c83c9784693f1e41b3cf87ff56e8f3caf7d42ff16c0ff97e987099aea75491a3946ab7b27c70c4d95f7a8a3f21e0baaa732983f0ae515f663c073cc11cf7183c7ccbb10e203c1b32386a6180f3b623c6230cafc616014ff8e00cf11473c470d1e33ef42880f02cf0e199a623ce888f190c128f3078151fc3b043c871cf11c3678ccbc0b213e043c3b60688a71bf23c60306a3ccef0746f1ef00f01c70c473d0e031f32e84f850f06c9fa129c6bd8e18f7198c32bf1718c5bf7dc0b3cf11cf7e83c7ccbb10e2c3c1b33d86a618ab1c31ee311865be0a18c5bf3dc0b3c711cf5e83c7ccbb10e223c0b3dd86a618773962dc6d30cafc2e60acd2f1ddc0b3db114f95c163e65d08f172f06ca7a129c61d8e18771a8c32bf0318c5bf9dc0b3d311cf2e83c7ccbb10e215e0d97643538cdb1c316e3718657e1b308a7fdb8167bb239e1d068f997721c4fb8126bc5d40dbaae39d41dba2e39d40dbace3a5a0bdaae31d41dba4e329d036ea7809681bc40fd0d6eb7807d05ed1f1f6a0add3f1aea0add5f16ea0bdace3dd415ba3e33d407b49c77b82f6a28edf09da6a1def05da0b3ade1bb4553a5e06da4a1def03da0a1dbf0bb4e53a7e3768cb74fc1ed096eaf8bda02dd1f1bea02dd6f1fb405ba4e3f783f6bc8e3f00da733afe20680b75fc21d0c6eaf8c3a03da1e38f80f6868e3f0ada9b3afe18686fe9f8e3a07d4dc70780f6751d7f12b4b7757c3068dfd0f1a740fba68e0f03ed5b3afe3468dfd6f191a07d47c74781f65d1d1f0ddaf7747c0c68efe8f833a07d5fc7c781f6031d1f0fda0f757c0268efeaf8b3a0fd48c72782f6631d9f04da4f747c32683fd5f129a0fd4cc7a782f69e8e4f03ed7d1d9f0eda073a3e03b49feb7825681feaf84cd07ea1e3b340fba58ecf06ed573a3e07b45febf85cd03ed2f179a07dace3f341fb44c71780f61b1dc7ef68ff56c78b8378dbf74f83eaa918f296fc549adfe97823238d2c5b00690af5cd4875bfa328a86effe578a03469ffb78226edff16d0a4fddf0c9ab4ffaf8226edff26d0a4fddf089ab4ff1b4093f67f3d68d2febf029ab4ffeb4093f67f2d68d2febf0c9ab4ff6b4093f6ff25d0a4fd7f113469ff578326edff0ba095e9f82ad0a4fd5f099ab4ff2b4093f67f3968d2fe2f034ddaffa5a049fbbf043469ff178326edff22d0a4fd7f1e3469ff9f034ddaff85a049fb3f163469ff9f004ddaff374093f6ff4dd0645ffb14343926bc059a1c13be069a1c13be0e9a1c13de064d8e09df004d8e09df044d8e09df026da48e7f1b3439267c073439267c173439267c0f343926bc039a1c13be0f9a1c137e009a1c137e089a1c13de054d8e093f024d8e093f066db28eff04343926fc14343926fc0c343926bc079a1c13de074d8e091f8026c7849f8326c7840f419363c22f409363c22f419363c2af409363c2af419363c247a0c931e163d0e49820c78826a0c9fd6a3525bfe05414544ff99097309505f11e73702a83f87c28bb4c8bc978d690f16c25e3b9998ce72a329e36643c1791f18c20e35941c6d39f8c673d19cf6e329e5d643cd793f11c23e3394ac6d3948ca7808ce745329ecd643cb792f1dc41c6730d194f828ca79c8c671919cf40329e75643c3bc9787690f1dc48c673848ce73019cfe5643c8dc8785e20e3b99d8c671319cf6d643cd791f11492f15490f12c21e31944c6f33219cf27643cdbc8788ac9780e91f11c24e3b9928ca70919cf4a329e0d643ccdc9785a92f15c4ac6d3808ca72d19cf22329e21643c2f91f17c4ac6d38a8ce716329e2d643c07c878f693f15c4dc6739a8ce762329eed643c6f92f12c27e379858ce706329ecbc8781a92f10c25e3594dc6f32a19cf3e329ebd643cd792f15c42c6f31619cf52329e33643c6bc9786e22e3b9828ca731194f3b329ee1643cabc8783692f1ec21e3a922e36946c673828ce738194f11194f6b329e3c029e047004a0c9ff1b8026efeb9e014ddeef3d0d9abcebbb1d347937780168bfb668f9163e61f818347937631e6872bdff1168f2cce05cd0e4bc41f257f38b9a9fcf9f6f2967030bff479672ceb32c8bdb5b96290be2ddde98575970fefbd785c0318f84a735194f1119cf71329e13643ccdc878aac878f690f16c24e35945c6339c8ca71d194f63329e2bc8786e22e3594bc673868c672919cf5b643c9790f15c4bc6b3978c671f19cfab643cabc9788692f13424e3b98c8ce706329e57c8789693f1bc49c6b39d8ce762329ed3643c5793f1ec27e33940c6b3858ce716329e56643c9f92f1bc44c633848c6711194f5b329e06643c9792f1b424e3694ec6b3818c6725194f13329e2bc9780e92f11c22e32926e3d946c6f30919cfcb643c83c8789690f15490f11492f15c47c6731b19cf26329edbc9785e20e36944c6733919cf61329e23643c3792f1ec20e3d949c6b38e8c672019cf32329e72329e0419cf35643c7790f1dc4ac6b3998ce745329e02329ea6643c47c9788e91f15c4fc6b38b8c673719cf7a329efe643c2bc8784690f15c44c6d3868ce72a329e9bc978b692f1ac21e3594cc6936fe139ed8847de9d9475cbfce9af78de478dbc8f5e20791f36f23e7c81e47dd0c8fbe00592f77e23effd1748de7b8dbcf75e2079571979575d2079ef32f2de7581e4bdc3c87bc7059237f3798bfa3e865c639fd0bf09f83f8edbbddd11e3698351e6b703a368f85da4fe8e78a2ce79fa13e4adbc18a8e372af2f01ff1f088caeea547f8351e66d750ac7a51ee88827ea5c6d2041deca0b79c64bfaca13f07f1cf7cb559d1a6830cabcad4e1d069e418e78a2ce310711e4adbc907724e459d304fc1fc7057155a706198c326fab5338aed510473c51e7c64308f2565ec83bcff2ee5802fe8fdfe97655a786188c326fab5338cec450473c51e7f44309f2565ec83771e4db0209f83f7ee7d4559d1a6a30cabcad4eed059ee18e78aa0c9e2a8b175f56deca0be963d8a37f13f0ff11c0e8aa4e0d371865de56a7aa806784239ea86ba81104792b2fca755cfa1613f0ff72607455a746188c326fab53bb80a7dc114fd4b55f3941deca0b79c65d9ecd4bc0ff71dc5c5775aadc6094795b9dc271e82b1cf1445db356d443de51d75ff59177d4b5447de41d755e5c1f79479de3d547de51e72bf59177959177553de61d751ca98fbca3da44bf7ffbfd3beebcbfcc6349959177553de6fd65eedf5f669bfa65b62dfebcc5b76bf595b73f6fe13e6ff92cbebc93787dda24c6f5e27d816dfa17efed6c054deeb56c014dee976d064dee79be0a9adcb7de049af43d6c044dfa8fde024dfa00b16f52bef97b1c3479260dfbc4648c89a3a0c95814d817f32b1d3f0cda1c1dc73e80d93a7e10b45fea38de7b9ea5e3fb41fb858eef036da68eef05ed431ddf03dacf75bc0ab44a1dc77b3c33747c17681fe838de5b98aee33b407b5fc7df046d9a8e7f0ada7b3a5e01dacf2cda541ddf00da141d5f0fda4f75fc15d026ebf83ad07ea2e36b419ba4e32f83f6631d5f03da8f74fc25d026eaf88ba03dabe3ab417b57c75f006d828eaf02ed873abe12b4f13abe02b41fe8f872d0beafe3cb401ba7e34b417b46c79780f68e8e2f066d8c8e2f02ed7b3afe0968a375bc1cb47c1d1f015a031d1f0e9abc17341434f9d6eb10d0e47dee41a0c937df0782d644c7fb8326cf92e37834f27d491c8f46de01c4b16ce43bd31f8126df6ec0b167647c101ca346be71f52bd09aeaf81cd0e45bb2b34193f7c57f099a7c537e1668f29d9f5f8026cf86cf044dbe17f92168f28ee1cf4193ef58578226df8698015a331dff0034f966d574d0e4bd9df741936fd54e034ddeb77e0f34f966fdcf402bd6f1a9a0ddace35340bb45c77f0adaad3a3e19b4163afe13d0e4db13934093ef2dfc1834f966d88f406ba5e313419377279f054dc6b77917b4363a3e0134f98edc0f416ba7e3e3416bafe33f00ad838e7f1fb4a48e8f03ad44c79f012da5e3ef80d651c7c78056aae3df03ad938e4bbba0f63fb55fbea6e7cb82f8cea7547e678373a73c63be0ce2c2803c719e6315010fe6752af6b2a792f8cc53be5eafd4975390f789d8f34ea6f33ea9d755a0d77bc2c8bb00d2fceddaea6d734c6b0df472a78de5f01a58d62dcbb405fdb8b1eea6babc271d95f784c124dce883a469a01b4d752c3ba8e38e9ea54aa97d40ea5a001ee25406717c5e307eaf52493c07af0dcf49e0897f3f4996b8aa13b86fc5d986d8ee019975ad08d2e09893c71df887fbbaac5be6253fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a47fa13b0cf5cd2bd46c2281af6759d8c9f27897daeb27ed5afb311fa755cf7ef35d4eb6d6794b900d27c047d4e5b74bc10fe2fdb2d6a5b3ae827ac715b4a7e85509e93c0e3a2bf380ff292759fb27821f1e2d8f24e55b8f1389554cf99a83ef6d386afaf593c75b5bf62df2d7a8afbeb598307fb460b81f775fd9b80f5bc0e6570b08fd7582f243fdc974e8126f1b3c0e8623be3b144da83b67a1efba625cd69edadf48bc7bfed534997edc631285359707efd2e80346f40dbf7968ee3b321af816fef5afe2f534dfdd4e29f2af391f8cb9cc467e065fb1eb1e47d085863cafb9ce7eff374907c442f80f80fafab4e2be9c40ff15ad8f1fbd6c86e2e77d658ae08d21cb594bf2c88b7fc470c9e2306b3da266f433d7b178effaedaa4a3111eb5058f240d9e07b9fa668fd9460a87e4a7d2c8f66f64a4c1731649f301b451aa2cd2ce4b39f1d9163c06b83a8ebd66944fe66de7c62781d12ca3aa1fb32fabe6bdd09ffffa03b417713ffff507a843f89c5660acbf1dac5fb81a05d1c71649f367e338eae21a03b7a5e927fa2c69fe02edd00dfa61dc6ccef5bfacebb6a873fda30e7812c1b9d7de6aaae9f88ec798630e781c9533693b761d37ca5404695a40391d9cc7d4f81ee111c8dbc536472fe41cea84e14501a4f99f46db11e5235eab9eac97b2a4ace783ed2c6591349f19edd461074c2eb7db2128935aef294b59254d8366d5be34d4f1046c27bc6f72a5e5ff32d5d41e887faacc07e22f7312dffd94ed7bc092f73e608d29ef73de3b95f37dc947f402885fd1ac3aada4133fc46b6157fb88bcdb86ece672278ce58a20cd414bf9cb8278cb7fc0e0396030ab6dd204ea99d42397ede6c1088fda81479206ef1fcbb11ddf6fb41df75d3c5f5dd371ff14309aed269ebbb86433bf0b6bde43b59d0f4a1a3c279334b768e6a6c1b9efe3609bb3d1ed33ff25f8fe6a00e5088cb206069b239f4bd167f31e601bd04d9fe57fb66b86b6e0737ddc9f166ef35a00af4784db3ccee0f5480970ab7a2fdb09ef238af686fe75744e5e8ad75b728c31cfc9f13e5a1760c76585eb754b59c403499b0fff97ff7d16d8af4f3e6f39337ec65846f9fb8691ce964f135836b677354a924993ffb4c1896db3a4b3f92afb01d6395997b9afe07d5149d3d76893ccb46adb4f6d5aed8f6c47f10edb13ac93aefa60ce18e59779c94f31ca3da033c0e3e23e4ab6ef4fb9becfe6a88d4ee2bd8bf8beffd06d94ed9ecb6b865745c1f9f7335cb6e9517d39272c79c7e7456ab4adbfdfe6457df6f7477971dc92777c5e74aeb0b573362f8e59785cdc7fa9c98b6396bc63f462aced9e88cd8ba3161e57d7db515e1cb5e41d9f175dacf7ab6c5e1cb1f0b8baee8af242f2cb96f918017313231e4fdea5a3f0be544d5e1cb6f0c47f4faa662f0e5bf28ecf8b92ce35f57fa217872c3caefa31a3bc3864c93b3e2fba76b3ddbfb07971d0c273b09ebd3868c93bc67a31c6767fc9e6c5010b8f837b8d357a71c092778ce7879df15e634d5eecb7f0ecaf672ff65bf28ed18b72db7d509b17fb2c3caeee834679b1cf92777c5e8ceaa4f2de5b0b2ff65a78f6d6b3177b2d79c7e745795795f79e5a78b1c7c2b3a79ebdd863c93bc66ba874bda8aa851755169eaa7af6a2ca92777c5e8c4e9f6bedae8517bb2d3cbbebd98bdd96bce3f322993ea6eeaa8517bb2c3cbbead98b5d96bc63ac17e9ebc99db5f062a78567673d7bb1d392778cc79174bdd8510b2f76587876d4b3173b2c79c7e7c5d8f4fda7edb5f062bb85c7d5b88c515e6cb7e41de33d9774bdd8560b2fb65978b6d5b317db2c79c7e745c7f431756b2dbcd86ae1d95acf5e6cb5e41d9f1763d27d625b6ae1c5160bcf967af6628b25ef18cf3bd3edc5e65a78b1d9c2b3b99ebdd86cc93bc6f3cef4fd8b576be1c5ab169e57ebd98b572d79c7d876a6cf3b37d5c28b4d169e4df5ecc5264bde319e77a6bdd8580b2f365a7836d6b3171b2d79c778de993e8e6ca885171b2c3c1bead98b0d96bc63ac17e9b6737d2dbc586fe1595fcf5eacb7e41de37dad74dbf94a2dbc78c5c2f34a3d7bf18a25ef18af47d2f7f8d6d5c28b75169e75f5ecc53a4bde31f615a5cfc1d7d6c28bb5169eb5f5ecc55ac8dbd5fb3a92873c8bd5daf0a200d2fc87f12c56948fb20e7cae0ccbf272ec65c93c57b626a22c2f435924cdff369ee55be380c95159d375e62528935aef594b59258d7c085ff992afe309d826af836f9759fe2f534dcf20897faaccabe32f73baaebe009c65900fe6bd0a5863cabb04f39667d3251fd10b20deb479755a49277e88d7c2aef69117751cd9cde5d61acb15419a172de52f0be22dff6a8367b5c19c7eef01ea99d423376d5786e9c5088f5a834792069fd93beb88c77c865038243f9546b67f23238d2c5b0069aed31eca73bbf21ca49433119cffdca4a3b6ac04d965dd322ff9e1fbb2a780d12ca3aa1f83e1d9cf0e5a6f1f546b25c20deb29353455d64e8eca2a79c9ba65be1330ca9814a5f5cf98aa2d63478351f17471e0198eb321534dc78b2ec0d3d9018fa372a68f435d8d327532ca540469f0ddc6ae0eca9907f9caba65be2be4ed629ba317724cbeddf0a200d27481f6ac261f651daafe965acad2c3715964ddd22ef5a887bcbb1979a78cbc13c1b9db39086adebfba01737707cc6abd3de35f6f7affba53af4bea94e4938232f5020fe22a13e62de779928fe805107f18cef3249df821c72f61577559b625b29bcb7531962b82343d2ce52f0be22d7f4f83a7a7c1acb6491f38b773b03fa4eb400f8343e653e05dcf08ef7a807792068f7f1d1c79d7dde091f90ec023e7385d41937305e14fc0ff93f5c06db67b5d2ddca27503c60e16c6d2f819d3e73a1d0c46992f0546d1ba034f37479e99dbfa76c31f3c2e3732d2c8b20590a61c8e8d094b5ab5dffd2b944bc62e8c719c9f749bdec8815f38ae6200fe04868701f825e56ce880e7e2a07a6cc5199553a6973f33a6ff984cd7a3a0151898f89b6729463e68186f60d182e0dc21240b409321241b82966fd88243574a7a19d2ce855de887acbbc0e06c022c71e68dc36fca5453d5690c3c2eaab2aa3a97e875e9aa3368faf8ca31583f1a1a9c75a93bea7f0d6a4817b52e57dbc1dc27ca60deac83058ef26f00e52d8379c94f6d9b421d9f5a5ef16c9fe9cfcc9c346672e50c34cadcb1319e179cbb01ccdf28c35ded745801b0c0d8383434ca850d86fc4f36ccc5f17396e218b7a63701e427d3c5e0db450e7c53eb97b16a2bca274eec3773d4c4f1157d674eaea81c3f65326ecd268673515b5afedf08345b138f69d584cd162edbd8a2d9261c15b8096872e4ba0834e1b918b4061097f4e69671525d5bc0fa659752ff53e634d4056f1c545701391cab7655edbfea54eed220732a745990d99c6aa86135b4b01a4a580d1dac860a56a36caaaf5aa89e1c75f6a486f65543f9aaa17bd550bdc5416628de5b82eaa176d5f42e70de16644eb5d4d0b9ad82ccd0b8ea76a57a5d5d7dda4d7d4a439db2ab534b759aab2eebd42588baada64e3dd52d0b75fb4a9dc6a9536475faa74ed9d42588baf450978aead2a9b7f6ba4f18ee0ac3dd61b8270cf786a16f18ee0bc3fd6178200c0f86e1a1303c1c8647c2f068181e0b43bf303c1e6486921e10862782cc50d34f069961a807079921aa9f0a32c3570f0b32435b3f1d6486bd1e196486c41e156486341f1d6486ce1d1b6486da1d176486f09d106486069e1864861c9e1c6486329e1a64864856c329aba197d590cc6a486735fcb31a2a5a0d213d370cf382ccb0d30bc2b0300ccf85e1f920336cf7e22033ccb71afe7b5990192e5c0d23ae8617575d09aa0b45752da8dbf6aafb4add5a565d5aea96b7ea8a555dd3aaab5e3dbaa01ee5508fb6a8477dd4a34fea5130f5689c7a54503d3aa91e25558fd6aa478dd5a3d75541e6d1fcbd41e6d50df52a8b7ab547bdeaa45efd3a1c645e0d54af77aad725d5ebbfea75e89341e676b67ab55e7571aadbd8ea96bebad5ad6ebbaba1e5df0ac3d7c2f0f530bc1d866f84e19b61f85618be1d86ef84e1bb416658e27782cc10c83f0832c328abfaa8866cfe719019f6f9a7416688e9f782cc30d51f049921b13f0c32c36aab21b8d510debf0e32c380ab61bfd5f0e7bf093243daff360cbf0bc3df85e1f761f84318fe3e0c7f0cc39fc2f0e730fc4318fe310cff1486bf84e19fc3f02f61f86b503df4353616bfd73337ebf9f2caca3193a65616574e299e347362e5f8a913e716cf1e5f39ae78caac31d3c74e9c321b175ea39b2719b7bbcff4e9e5738bc74f1e3d664ef1949995c553c6168f9a3273f2e8730ed4c7f442d79f9f63f9e8d1d1997d23ff0b907ea78e99bea7979311d11fa8b96c3faf8b211fd565a1ff55c702cdd1472fb97d322073ae5b3c63e294cae264f1e4f06f78709d327bcce8f6c5f8bf19a1c9332a8b6754964faf2c1e3b7dcaa4e292f6b8de8f1bd7a110ffded80dcc2557d5cd9ccff4f8ce75aa62a7aeab8303ef5f5737d2df5ff70548ff54c74cff475d4af87febb2d0cdcdea46d8a659a42d33668eaa9c5e5e5119bd70f28b2cdcb9591d8a796f1d8bf9dfeb92d97fd665a16b9bd78db073f33a6436328bcc82ff07d6af973f08fc0400", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9df7771c45b6c77b64490e638de51c018171906549a3916c598e12b08071029b60927192c1605bc61669030b1b6161173692173647364736e765132cbb0b0bcbe665c30fef0f78efbcc379b77aea3e7d55aed6d1882e71dbdc3ee7baabbfaae9fad4b76fd78cab7b7a725179f93745ce96c750cc8f8e5df8efdd765d7c694b5b8afb2a86e4cc6584b32a239c6332c2599d11ce9a8c70d66684736c4638c76584737c4638276484339f11ce8919e1accb086721239c9332c2599f11cec919e19c9211cea919e19c9611cee919e19c9111ce9919e19c9511ced919e19c9311ceb919e19c9711ce1332c2796246384fca08674346384fce08e7292972360127cf859f6ad70bec7aa15d2fb2ebc576dd68d74b6c1fabedb6d9e7528a668a16e76fad8699c24c8a979cbfb55374502ca3586effd660ffd649b182a28b6225c52a8ad5146b28d652acb39ef4509c46713ac51914afa23893e22c8ab329d6539c43b1816223c5268acd145b28cea5388f622bc5368af3292ea0b8d061b988623bc5c51497505c4a7119c5e5143b28aea0d849b18b6237c51e8abd14bd14fb28aea4b88a623fc5d514d7501ca038487188a28fe230c5b51447288e52f4535c4771bde3d90d143752dc44f16a87f33514afa5781dc5cd14afa7b885e2568a3750bc91e24d146fa6780bc55b296ea3b89de26d147750dc49f1768a7750dc457137c53b29de45f16e8af750bc97e27d14f750dc4b711fc5fd96854f8407281ea47888e2fd140f533c42f1018a0f527c88e2c3141fa1f828c5c7283e4ef1098a4f527c8ae2d3148f527c86e2b3149fa3f83cc51728be48f1258a2f537c85e2ab145fa3f83ac56314dfa0f826c5b728be4df11d8aef527c8fe2fb143fa0f821c58f287e4cf1138a9f523c4ef133c7f39f53fc82e29714bfb2da1376fda45dffdaae9fb2ebdfd8f56fedfa7776fdb45d3f63d7bfb7eb67edfa39bbfe835d3f6fd77fb4eb3fd9f59fedfa2f76fd57bbfe9b5dffddaeff61d72fd8f53fedfa5f766dae8fe52797cbe3a281a53b4a69cce9e8ed32f3e36ca67bfdcd5cdb1963ffc6eb06ab57db6d5ee7ac5e63b76b1cbdd66ed73afb1967b7c7397ac16e171cbdde6ed73bfa14bb3dc5d1a7d9ed698e7eb2dd3e19f4bcfd5bb963e595d1c65829071ae75f156835561b035a2def0eb4b156ab018d8f6f2d68e3ad3616b409561b075ade6ae3419b68b509a0d5592d0f5ac16a13419b64b53ad0eaad5600cda6663409b42956ab076daad5268336cd6a53409b6eb5a9a0cdb0da34d0665a6d3a68b3ac3603b4d9569b09da1cabcd026daed5668336cf6a73403bc16a73413bd16af3403bc96a2780d660b513413bd96a2781768ad51a40e3f3f264d04eb5da29563339c5e35cfc1aab5781762a9fcba02de0f318b4857c0e83b688cf5fd01643dbac35f2f90cda12ab713e9bbf2db7e5ee28adb1acb4dbecb733edfdd29ecd7ebbd2df6fd18c8d2ba301afbba19d4ef06a952da7784f401bb69db3c1edb05e0de533a12ed7633f784c627633ceacb0e55543bc6eb9f3ba02d459e1e97f77946effbb1c9e2e87b906ca8172769fe6ecb0978a73f67ca8ebe61ebf3f1e8f39bb1e38d2cfd9f676cdd9612f15e7ec6ea8ebe61e7f563b1e73f622e00890b39d6172b654d49c2dcf8f44913ff7f8ff0dc763cef60247fa39bb4c7376f84bc5397b33d475738fff0f7b3ce6ec51e0483f673b3bf5b3c1b0978a73f64ea8ebe61ecfa71c8f397b2b7004c8d9dd3ace0e7ba93867ef87ba6eeef1dcdef198b3770147fa39db152867db3567a3f2b5ae28f2e71ecf331f8f39fb1070a49fb37b747e76f84bc539fb15a8ebe61e5ff3381e73f653b66cae333c61af33cc03ed49ab9d00daafad7622684f59ed24d07e03d70659fb2d5f3704ed77563b05b4a79d6baa467bc66aa782f67bab2d00ed59ab2d04ed39ab2d02ed0f565b0cdaf3566b04ed8f565b02da9facd604da9fadb614b4bf58ad19b4bf5aad05b4bf59ad15b4bf5bad08da3facd606da0b562b81f64fabb583f62fab7580f66fab2db39ab926c9d7be7e6cb571d0f7ee28bd1c8daf774583979cb3dd0de52561798a8568f07d40dcd6d2f4db6a377d6f8a86dff7a5c0d31ca0ef796863383ccdc0d3923e4ffc3db9d6f4f71b1fe326c7d33cb4d504fd2a06e8570edae27df336b757000dc78da287b12d7dc612deebc4fbe6ed3660640dc7311e87f9fc31ef31ff01de00e752fc3983dbe3efff32c752d0b9ced7eb07d8fecb6a75f0771cd35b1c2d505ec679c16df1be79bb1518b93f2da3cf581a2e63b3c3186a8cc8415bbc6fb76d3cdf978cbe67c33aae05d05e8631a934d231a90ed81a81b131908f49c75a4adb21deaf72d0068f6dec792be85ce7d9aaf2da8c6d1372036c01cebf52a59fdf703c483f8f4b453caf87c353049e10e77ea0f3b588effb2f46e9e65ac9f1aac5f1aa0075dac0bf5200ff86fa1cc2ed29b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb37c66bcff02af6f72bd46218cacb5024f8879fef8bbe4bc2fbb36d7751e80eb3ae95fb72815f19a25dfb7b7d0e97335d479343750f7615bf65d1bc46b9a8d61bd1bd67d1675d1b1d762435e434cba0eecbb7ed9905adba53da1aeb799e75c9867123439be367a3c0d709fca204f738ea7787fdc6287c7e4e9f355036c21aefd557a2d12bde2729ad7f6f01e83b0c7a53c7e702e544583c70f7c9f694fbdedc1d730f97a79bbd37635d4f9466ee0d8f03d90fc5b07ee3d4fa64e87b36f7ecd42d03b9c7dd7dbd732478db3ff26782dd7f9368ca9bb205743dcff81e372047dc5a51bca78dd3cfdf7e1f275fc62053c25e00931ce04fabc51c47320edebf81d8e57becf315ca71dfceb08e09fefb3286f737bcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9f19bf2bcaac79a8d72a847194ee7d88af67f0734778ffe6bace96aa8176435f87e36b4e8b9c3e57439dbbab06ea6eb3e5bae8d8fb1d928e6580eb79431e4b6eaf0efa83d782427d9fbbcde169f378c1e586d4da2e5fc74fdfe381ebf845c7d7568fa7a1ce57bcc68a9ee2f9dae2f0e0b5d1bae8d87b4bf2b09fd1b87728292fb83d3c97da40e3327e3f3ac471c6f712f7be1e6e0faf5f5f63bdad8f421dfb5231e4b8b10cfad41d1d9bdfd550e7308c7d476c19efe1c07b476ef5fc9d97a1ae53b37f819ee3161fdf15c0d90ded60db5dc09a52db6dd876ce06b7c37a35946fa91aa8eb3ea78cbd6676738eb8cf52f3bdaec5795d01ea2cf7f4bf3b4ab7ff9d0e4fa7c36c8ec9759067b7c2fb7fa831697982470bc123ae839f8342bd77baf757baf715e2385aebd4e1d756439ddb618c4aba7fd4f71e10fa7d8cf7ed7b1f73df1786739fe72bfd3eadfb60bc48fb3eadfb2087f03eadc8d9ff22d83f73d546c9ef2d5ce72167ffee67727e0dde07c6751e81f1e229f8ace37efec67ba646e3ff5749f749737bf8b986ff369cbe1be66550bf3b4566cc0964c1cf095ce793ce31eb48e05eea79eda309af65aff83954f8ff17d73fe343eacf90b5e77ca7d317ceebe5d017aef345e73360a8e77ca7dfd7c19f49781c68f3f495eb7c0dceb5c7e0331e1f27fc7fc7e39ebff332d467407ceeedcaf4fb1c1f5f7cbe6b37b4836daf06d694da6ec3b6f93320b7c37a35947f0a633ad7633fd86b6637e7087f8e4276f775edceeb0a50a7cbd3ffee28ddfeaf7478563acce6987c0bf2ec71f80c186aacee4af0681178c475f0bb41fc3e82cf90f5cd75bc5cff9fc6cf52383e3f15745ecdfffee7ceabf93e232c723cc6cf08cfc0389bf7d475e70bf9fd32cdfb86f1bb124dd0eef39e76bb53f6b3197ceb866dfc5cf072b61de0b9a5f17744f0b982cc804b379499a100afabca00e3980c30566780b126038cb519601c9b01c67119601c9f01c6ffffbd6fc18cf90c304ecc00635d06180b19609c9401c6fa0c304ece00e3940c304ecd00e3b40c304ecf00e38c0c30cecc00e3ac0c30cece00e39c0c30cecd00e3bc0c309e9001c61333c0785206181b32c0787206184fc900e37c654c85717158c6d248190d4fa8df27ace437f146e3f709977ada0a705da45469dff15a4988e7a755fa7b89cc50888efdfdaf408ca591321a9e96f4792afe7dcd16f0ccf73b9801185fd26f48497a6e1bde9fbe242c63e9a53c5b2ec4b31647fafc30bcc7604958c697f48cb310f71054fa8c33dfef6e2e09cb581a2963a87b42f0fe93e1f0f8ee13591296b13452c650df83c0ef6a0d87a71d3c2b793c0bc0581a2963a87ba62abda70fefed6ef77826891179d27ebe68bba7ad6502face0c59631c9f01c6091960cc678071620618eb32c058c800e3a40c30d6678071720618a76480716a0618a76580717a06186764807166061867658071760618e76480716e0618e7658051ff5fa88c2f3723f234a4c73368fe03db0af1bdd64afbbedcc393e2f73e07f51ddb0af08c938afb8ecf02c912e3b20c30067e9e8dfaa88ccaa88c7a5eab8fe219d547f5511995511995f195ce9885315c1933918fa591321a9e15813cebac80670578c6af5b1296b1345246c313e2d9b8796863383c5de0d90a8f6701184b2365343c019ee3177bd655010f3eefaecbe35900c6d248190dcfaa409eadac80671578b6d2e35900c6d248190d4f886716e6a18de1f0ac06cf56793c0bc0581a29a3e159933e4fecd9ea0a78d68067ab3d9e05602c8d94d1f0ac4d9f27f66c4d053c6bc1b3351ecf02309646ca6878d6a5cf137bb6b6029e75e0d95a8f6701184b23651c077a8a3cb167eb2ae0e906cfd6793c93cad89101c6651960cc828fcaa88c9218f5bc561f2531aa8feaa3322aa332669771790618f5582ba354c69ef4194b9532f6004f77fa3c6d81fa19fffed469765f293e13a164bc3addf16a9de35501ea9c06fe9d1ec0bf1cb4cbfbe66d6eaf52e6530530076abbc4bf8bbcce696f99e38759ceb0eb1ad0f137dc5f65cbfcdb735c1f7f878ceb6cb63ff4c1bf69c94b15f4f78cf4fbdb36d4b9cded214f8b309ea5c2787a84f1cc15c6335d18cf1a613c9384f1ac14c6335e18cf42613cf8bb5b12783a85f1cc13c6b34818cf0c613cf5c2782608e32909e3a916c6d32a8ca74918cf7c613c3385f1ac15c6335918cf62613c79613c2b84f1d408e359258c6781309e59c278a608e399288ca756184f51184fa3309e66613cb385f14c15c6b35a184f9d309e2e613c6385f1b40be399238c679a309e82309e71c278da84f1e404f0e4a363ef59c8c3df7b40ab725e6bc6abffad1ff8fb9956af82d79c65cb633cfb3e1334beb67b96e7b5e8d399d0976e5b2ebeb425f609dbea866d6eaf0e38ce12c2d3268c679c309e82309e69c278e608e36917c63356184f97309e3a613cab85f14c15c6335b184fb3309e46613c45613cb5c278260ae399228c6796309e05c2785609e3a911c6b342184f5e18cf62613c9385f1ac15c6335318cf7c613c4dc2785a85f1540be32909e399208ca75e18cf0c613c8b84f1cc13c6d3298c678c309e85c278c60be359298c6792309e35c278a60be3992b8ca74718cf52613c2dc278aa3c3c3d8178f8fa2def9bb77b84b41de038c4df8b3f3b509fd6db7dd5d8fd323fb7570d75eead2dafcde75d7c2d73b9d7dbf15c5e0f1ead0fd4173e1e39e7f8046ebb03ef2b88802172fc893c3c21eec708d4cf417998e2f3198ac6ab731cafdc6357803a67837fe704f0cf97dbbccded29b3322731e3ef32306b1eeab50b6164ed8ca03c1dc54a7f3be21ce009f15e11c8f7781cdbe0f4a9dde33bd7c15cdd10a09fbe7387b73778da6e88d2f562e330bcd8e8e1d938ca5e707b95329f9d4166f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466093e1b1efe8e34b3e6a15ea71046d6d687e589bf6fd4190d5e72ce7637943702cf3901fc09d4cff81ef24d4e9f3a3dbe731d3cbf3605e8a7efdce1ed4d701c2a61de904166f57964cc86879f75c5ac79a8b74208236be784e589c7b115d1e065a8716c13f08418e703f5331ec7363b7d5ae1f19debe0f9b539403f7de70e6f6f86e3a0cccaec63363cfc8c6066cd43bd2e218cac6d0cca538abfdfd8150d5e861ac736034f88713e90eff138b6c5e95397c777ae83b9ba25403f7de70e6f6f81e35009f3860c32abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3fafccaf1d9f0f0b3ce99350ff5560a61646d53509ef6f8bac3ca68f032d475872dc0b339759ef2758700bec7d71dce75fab4d2e33bd7c1f3ebdc00fdf49d3bbc7d2e1c87e39d7943069935374687597343999398353794398959734399939835379439895973439993983537943989597343999398353794398959734399939835379439895973439993983537943989597343999398353794398959426e189e55b6ccac79a8b74a08236b9bc3f2c4cf3d58150d5e86ba6fe75ce0d912c09f40fd8cefdb39cfe9d32a8fef5c07cfaff302f4d377eef0f679701c9459997dcc8667b52d336b1eeaad16c2c8da96b03cf138b63a1abc0c358e9d073c21c6f940fd8cc7b1ad4e9f567b7ce73a98ab5b03f4d377eef0f656380ecaaccc3e66c3b3c69699350ff5d6086164eddcb03cf138b6261abc0c358e6d059e10e37ca07ec6e3d836a74f6b3cbe731dccd56d01fae93b77787b1b1c076556661fb3e1596bcbcc9a877a6b8530b2869f7f98edc5f478961580a50ada0a3586474edf79c17ce1a54518cf52613c7385f14c17c6334918cf78613c0b85f18c11c6334f18cf22613c3384f1d40be399208ca7248ca75a184fab309e26613cf385f1cc14c6335918cf62613c79613c35c2781608e399258c678a309e89c2786a85f11485f1340ae36916c6d3238c67b6309ea9c278ea84f18c15c6334718cf34613c05613ce384f1b409e3c909e0c947c75ee7c4eb276340e3eb196b413bdf967b40abf2b4c1fbd9061acf17f03ecc783376f2b1ed5579dadbe6e11a0d3fb1ad6ed8e6f6ea80639b109e36613ce384f11484f14c13c6334718cf58613c75c278a60ae3992d8ca747184fb3309e46613c45613cb5c278260ae399228c6796309e05c2786a84f1e485f12c16c6335918cf4c613cf385f13409e36915c6532d8ca7248c6782309e7a613c3384f12c12c6334f18cf18613c0b85f18c17c6334918cf74613c7385f12c15c6d3228ca7cac37341fa3cf177ca7aa2c1cb50d7642e08ec4fa07e16cd7e2fb4fb4af1bb2cf177d52e72bcea71bc2a409d0bc1bf8b02f897837679dfbccded29b33227311b1e9eebc5eba55caf5908236b5bc3f2c4e363733478196a7cbc0878028c636d81fa198f63db9d3e357b7ce73a98abdb03f4d377eef0f6764fdb0d51ba5e5c3c0c2f2ef6f05c3cca5e707b95325f984166093e1b1efeeccaac79a8b75408236b1784e589c7c7a5d1e065a8f1f162e009f1fe11a89ff1987089d3a7a51edfb90e9e5f9704e8a7efdce1ed4be03854c2bc3d83cceaf3c8980d0fcff9336b1eeae1f7c05e4e46d62e0aca538a7fa3b2291abc0c358e5d023c21c6f940bec7e3d8a54e9f9a3cbe731d3cbf2e0dd04fdfb9c3db97c2715066655666655666655666655666655666655666655666655666655666655666d9cc8687bfbbc7ac79a8d7288491b58b83f294af3b34468397a1ae3b5c0a3c21aecb04f23dbeee7099d3a7468fef5c0773f5b200fdf49d3bbc7d191c076556666556666556666556666556666556666556666556666556666556666596cd6c785a6c9959f350af4508236b9784e589bfb7d5120d5e86baee7019f084b82e13a89ff17587cb9d3eb5787ce73a98ab9707e8a7efdce1edcbe13828b332fb980d0f3f1b8d59f350af5508236b9706e5295f3f6d8d062f438d6397034f88713e90eff138b6c3e953abc777ae83b9ba23403f7de70e6fef80e35009f3f60c32abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3fafccaf1d9f0f06f9c316b1eea158530b27659509ef6f8ba43311abc0c75dd6107f084b82e13c8f7f8bac3154e9f8a1edfb90e9e5f5704e8a7efdce1ed2be0381cefccdb33c8acb9313acc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc1272c3f0b4717b769d877a6d421859bb3c2c4ffcdc83b668f032d47d3b5700cf8e00fe04ea677cdfce4ea74f6d1edfb90e9e5f3b03f4d377eef0f64e380e3b9559993dcc86a764cbcc9a877a25218caced08cb138f63a568f032d438b61378428cf381fa198f63bb9c3e953cbe731dccd55d01fae93b77789bdb5366654e62366def4ebfed783cc0b6d99fc8e1e16577602f02f5331e0ff6447e8fb9bd02d4c163be27403f73d02eef9bb7f7c071a884797b0699d5e791319bb6f7a6df763c1e60dbec4fe4f0f0b237b01781fa198f07bd91df636eaf0075304f7b03f43307edf2be79bb178e4325ccdb33c8ac3e8f8cd9b4bd2ff5b6cbcf49c3b6d99fc8e1e1655f602fc2f4b33c1e5c19f93de6f60a5007f3f4ca00fdcc41bbbc6fdebe128e83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66366d5f957adbe5f97b6c9bfd891c1e5eae0aec45987e96e7eff7477e8fb9bd02d4c163be3f403f73d02eef9bb7f7c3715066655666655666655666655666655666655666655666655666655666655666d9cca6edabd36f3bfe3e0eb6cdfe440e0f2f5707f622503fe3f9fb6b22bfc7dc5e01eae031bf26403f73d02eef9bb7af81e3a0cccaec63366d1f48bdedf2f53c6c9bfd891c1e5e0e04f6224c3fcbe3c1c1c8ef31b757803a78cc0f06e8670edae57df3f641380e95306fcf20b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfaf1c9f4ddb87526fbb3d9ebfc7b6d99fc8e1e1e550602fc2f4b33c7fdf17f93de6f60a5007f3b42f403f73d02eef9bb7fbe0381cefccdb33c8acb9313acc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc1272c3b47d38fdb6e3efb363dbec4fe4f0f07238b01781fa19dfff726de4f798db2b401dccd36b03f43307edf2be79fb5a380ecaaccc3e663c4fc6a5d7767c3f1cb75165d7463b62cb63403b6acbd5a0f5db720d68d7d9722d68d7dbf258d06e80feb076a32d2f06ed265b2e81f66a5bbe02b4d7d8f24ed05e6bcbbb407b9d2def06ed665bde03daeb6d792f68b7d8722f68b7daf23ed0de60cb5782f6465bbe0ab437d9f27ed0de6ccb5783f6165bbe06b4b7daf201d06eb3e583a0dd6ecb87407b9b2df78176872dcf07ed4e8ff6765bbe10b47778b4bb6c793c6877dbf204d0de09655ebfcb962782f66e5bae03ed3db65c00edbdb63c09b4f7d9723d68f7d8f264d0eeb5e529a0dd67cb5341bbdf96a781f6802d4f07ed415b9e01da43b63c13b4f7dbf22cd01eb6e5d9a03d62cb7340fb802dcf05ed83b63c0fb40fd9321ea30fdbf261d0781cb816341e078e80c6e3c051d0781ce8078dc781eb40e371e07ad0781cb80134ce9d1b41e3dcb90934ce9d5783c6b9f31ad038775e0b1ae7ceeb40e3dcb91934ce9dd783c6b9730b689c3bb782c6b9f306d03877de081ae7ce9b40e3dc7933689c3b6f018d73e7ada071eedc061ae7ceeda071eebc0d34ce9d3b403bc196ef04ed445b7e3b6827d9f23b406bb0e5bb403bd996ef06ed145bc67181c79f778176aa2dbf1bb405b6fc1ed016daf27b415b64cbef038ddf73ee01add196ef056d892ddf075a932ddf0fda525b7e00b4665b7e10b4165b7e08b4565b7e3f68455b7e18b4365b7e04347e9ffc0068edb6fc41d03a6cf943a02db3651e17ccf967ce19ee33fb5107fd6bf270b3360eb8bba3743f33715bbc6fde2e0223fbdd3afa8ca5e132b6388c86a714c033cc215e86fabf1f33189e36f87b5a3c81fa19ffdfafdde953d1e95301ea9c0afd6c0fd0cf1cb4cbfbe6ed76683bc431472f6aec7e17385e54439d27ed9b9c590de523efc3e46faba72fcb03f785f7cde3d2f25168bbc369bbd9691bc75e5e863abf3a8079590066b3dfcef4f71b9f5f2becbe38a7b89d66e853177890569fb0ed9c0d6e87f56a28bf503f5097ebb11ffcfec5ec2697f95822bbfbba92f3ba02d459eee97f77946eff3b1d9e4e87d91c93e7ea0738029c0f710e2c773878bb19bceb4cf06e3978c775f0fdaf259077cb1c1ede6e011efe8cd30e1a7f56c03908fe7bd32870bbe35ebb879bb50e606cf13036a7cf187fd669711879bb1918595b063c1d813c738ff502c71f7c5fae75eaf06baba1ceffc07b63de53d79c77ff817ef1ff995f8cd21dd36b03f885ff9f8fc09fc8f13002bfb89f350178264403ffa73fdadf7764d795bd5b7b77edcd015ab58389eb9ca71b55a061798c478ba2c1531738e5c9531738e559e5d88253265cdffc57ca748ba7077a0feeefbfe050efa13d476e3adcdfbb7763df95485de3d02369520f9014355f8f86a21f1f1d7bf0533d33196e3eec3f6741c6d84ed4582063dfb868c03e9ed931efd66644313335e68c343331c65a33d3626656cc4c8a99393133256666c4cc8498990f33d3616636cc4c8699b93033150d517926e214e0f931309aff2198b3ddcc24989903335360de25cca74f33b29a4f12669433a39b7917339f92cdff98ccc861466533e29851c2bceb99773bf3e9c4bc5bafa45845b19a620dc55a8a75d6eb1e8ad3284ea73883e2551467529c457136c57a8a732836506ca4d844b199620bc5b914e7516ca5d846713ec5055179e6efa2a87c85f3628a4b282ea5b88ce2728a1d5179467d67549e313733e46646dccc809b196f33c36d66b4cd0cb699b13633d4d744e5196833e36c6698cd8cb2994d34b38766b6d0cc0e9ad94033fb6766fbccec9e99cd33b37766b6ceccce99d93833fb6666dbccecda2d5179f6cccc9699d931331b6666bfcc6c9799dd32b35966f6cacc56dd119567a3ccec93996d32b34b6636c9cc1e99d922333b646683ccec8f99ed31b33b6636c7ccde98d91a333b636663ccec8b996d31b32b8f44e5d913335b626647cc6cc847283e4af1318a8f537c82e293149fa2f834c5a3149fa1f82cc5e7283e4ff1058a2f527c89e2cb145fa1f82ac5d728be4ef118c53728be49f12d8a6f537c87e2bb14dfa3f83ec50f287e48f1a3a89c933fa1f829c5e3143fa3f839c52f287e49f12b8a27289ea4f835c55314bfa1f82dc5ef289ea67886e2f714cf523c47f1078ae729fe48f1278a3f53fc85e2af147fa3f83bc53f285ea0f827c5bf28fe1d0dcca4e240f198dde059bd5dfdfdbd070ff737f4f7351cbcee40fffec3076e6ab8617fff550d7dd7f71ed977a0ef067cf1d57618e229cb9e234776ddd4b0ffd0dede1b1bfaaeeb6fe8dbd7b0bbefba437b8fe28b6eb32f9a776c8bbbf6ee4d6eecdeaa9740fae0081bfd847d1d4f06af1fba6f9f1e89215f18c98b9e1e618736d97791d5767b5bf99dbae1e881befe8662c321fa77d7017a4defde9606fcdb5132f9687fc3d1fe5d47fa1bf61de93bd8d0d682fbbda776049d78a27e042ffaeffae1f73cfa3fac10a5ab91130300", + "bytecode": "0x1f8b08000000000000ffed9df77f1cd5d5c667d55cd65acbbd0202e322abad569265b9ca40006363834d31cdb8c960b02d638b964220150209bca9d4407a25bd92de437a4842494823fd87fc0bf9bce7cedef3ead1f51dbd5a31573963ce7c3ec773e7f1ddb9dffbcc99bbab3bb3b3b9a8bcfc932267cbd5148ba2e317feff3ebb2ebeb8a523c57d154372e632c2599511ceea8c70d66484b336239c7519e19c9011ce8919e19c9411cec919e1cc6784734a4638eb33c259c808e7d48c70366484735a4638a767847346463867668473564638676784734e4638e76684735e4638e7678473414638176684f3a48c709e9c11ce5332c2d99811ce5333c2795a8a9ccdc0c973e1a7dbf562bb5e62d74bed7a995d37d9f572dbc71abb6df6d942d14ad1e6fc5fbb61a63093e225e7ff3a29ba28ba2956d8ff6bb4ffd743b192a2976215c56a8a35146b29d651acb79e6ca03883e24c8ab3285e467136c53914e7526ca4388f6213c5668af329b6506ca5b880e2428a6d14db292ea2b898e21287e5528a1d1497515c4e7105c595145751eca4b89a6217c56e8a3d147b29f651f453eca7b886e25a8a0314d7515c4f7190e210c5618a018a231437501ca5384631487123c54d8e673753dc42712bc5cb1dce5750bc92e25514b751bc9ae2768a3b285e43f15a8ad751bc9ee20d146fa4b893e22e8a3751dc4d710fc59b29de42712fc57d14ff43f1568ab751bc9de21d14efa47817c5fd140f503c6859f8447888e2618a4728de4df128c56314efa1782fc5fb28de4ff1018a0f527c88e2c3141fa1f828c5c7283e4ef138c527283e49f1298a4f537c86e2b3149fa3f83cc51728be48f1258a2f533c41f1158aaf527c8de2eb14dfa0f826c5b728be4df11d8aef527c8fe2fb143fa0f821c593143f723cff31c54f287e4af133abfddcae7f61d7bfb4eba7ecfa5776fd6bbbfe8d5d3f6dd7cfd8f5b376fd9c5dffd6ae7f67d7cfdbf5efedfa0f76fd47bbfe935dffd9ae5fb0ebbfd8f55fedfa6f76fd77bbfe875d9beb6333a695cb13a3a1a52f4a69cce9eaef35f3e36ca67bfdcd5cdba9b6ffc7eb46abd7d86d5ee7ac5e6bb76b1dbdce6ed739fb9968b7273a7ac16e171cbdc16e3738fa74bb3dddd167daed998e7eaadd3e15f4bcfdbf72c7ca2ba3555b29071ae75f1568b556ab06ad8e7707da04abd582c6c7b70eb449569b00da64ab4d042d6fb549a04db1da64d0eaad9607ad60b529a04db55a3d680d562b806653339a0ada74ab358036c36ad3409b69b5e9a0cdb2da0cd0665b6d266873ac360bb4b9569b0dda3cabcd016dbed5e682b6c06af3405b68b5f9a09d64b505a09d6cb585a09d62b593406bb4dac9a09d6ab553403bcd6a8da0f179792a68a75bed34ab999ce2712e7e8dd5ab403b9dcf65d016f3790cda123e87415bcae72f68cba06dd69af87c066db9d5389fcdffadb0e5be28adb1acb4c7ecb727edfdd29ecd7e7bd3df6fd18c8daba221affba09d1ef06ab52da7784f4007b69db3c1edb05e03e5b3a12ed7633f784c627633ceacb4e5d523bc6e85f3ba02d459e9e97f5f946eff7b1d9e5e87b916ca817276bfe6eca8978a73f622a8ebe61ebf3f9e8839bb1138d2cfd9ce4ecdd9512f15e7ec1ea8ebe61e7f563b1173f652e00890b33d6172b654d49c2dcf8f44913ff7f8ef86133167fb8123fd9cedd69c1dfd5271cede0675dddce3bf614fc49c3d061ce9e76c4f8f7e3618f55271cede0375dddce3f994133167ef008e0039bb47c7d9512f15e7ec8350d7cd3d9edb3b1173f65ee0483f677b03e56ca7e66c54bed61545fedce379e61331671f018ef47376afcecf8e7ea93867bf0075dddce36b1e2762ce7ecc96cd75869fdbeb0c0b41fb85d54e02ed97563b19b4a7ac760a68bf826b83acfd9aaf1b82f61bab9d06dad3ce3555a33d63b5d3417bd66a8b417bce6a4b40fbadd59682f63bab2d03ed79ab3581f67bab2d07ed0f566b06ed8f566b01ed4f566b05edcf566b03ed05abb583f617ab1541fbabd53a40fb9bd54aa0fddd6a9da0fdc36a5da0fdd36add5633d724f9dad7f7ad3611fade17a597a3f1f5ae68f89273b6fba0bc3c2c4fb1100dbf0f88db6a49bfad4ed3f7e668f47d6f019ed6007dcf431ba3e169059eb6f479e2efc9b5a7bfdff818373b9ee6a1ad66e8573140bf72d016ef9bb7b9bd0268386e143d8c1de93396f05e27de376f7700236b388ef138cce78f798ff917f0063897e2cf19dc1e7fff97395a40e73adf6a1862fbb7d5eae1ff714c6f73b4407919e705b7c5fbe6ed7660e4feb48d3f6369b48cad0e63a83122076df1beddb6f17c5f3efe9e8deab81640fb2f8c49a5b18e49f5c0d6048c4d817c4c3ad652da0ef17e958336786c63cfdb41e73acf5595d7666c9b9c1b620b70fe952afdfc86e341fa795c2ae2793d1a9e22f08438f7039daf457cdfff4f946eae951cafda1caf0a50a703fc2b05f06fa4cf21dc9e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6fb2ff0fa26d76b12c2c85a3bf08498e78fbf4bcefbb26b735de721b8ae93fe758b5211af59f27d7b4b9c3ed7409dc77343751fb565dfb541bca6d914d6bb51dd67511f1d7f2d36e435c4a4ebc0beeb978da9b55dda1bea7a9b79ce85792641b3e36b93c7d300f7a90cf334e7788af7c72d73784c9e3e5f35c416e2da5fa5d722d12b2ea7796d0fef31087b5ccae307e74255347cfcc0f799ced4db1e7e0d93af97773a6dd7409dafe4868e0ddf03c9bf75e0def364ea7439fbe6d72c01bdcbd977837d2d73d43afb6f86d7729dafc398ba1b7235c4fd1f382e47d0575cfaa08cd7cdd37f1f2e5fc72f56c053029e10e34ca0cf1b453c07d2be8edfe578e5fb1cc3753ac1bfae00fef93e8bf236b7a7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1bba2cc9a877aed4218c7e9de87f87a063f7784f76faeeb6cad1a6a37f47538bee6b4d4e9730dd4b9af6aa8ee765bae8f8ebfdf21e95806b89e37e2b1e4f6eaa13f782d28d4f7b93b1c9e0e8f175c6e4cadedf275fcf43d1eba8e5f747c6df7781aea7cc56bace8299eaf6d0e0f5e1bad8f8ebfb7240ffb198f7b8792f282dbc373a903342ee3f7a3431c677c2f71efebe1f6f0faf5f5d6db8628d4b12f15438e1bddd0a7bee8f8fcae813a4760ec3b6acb780f07de3b7287e7ff7919e93a35fb17e8396ef1f15d099c7dd00eb6dd0bac29b5dd816de76c703bacd740f9f6aaa1baee73cad86b6637e788fb2c35dfebda9cd715a0ce0a4ffffba274fbdfe3f0f438cce698dc08797607bcff871a93562478b4043ce23af83928d43d79ee18e9dedf88f7edd53975f0330bd7b90bc6a8a4fb477df71c867a1f4bbae7d0f7d9b8048c6e1fddfb3c5feaf7693d00e345daf7693d003984f76945cefe97c2fe99ab2e4a7e6fe13a8f38fb773f93f36bf03e30aef3188c174fc1671df7f337de33351e7f5f25dd27cdede1e71a3cb7ffbfbe1be66ea8df972233e604b2e0e704aef351e798752570b7785efb78c26bd92b7e0e15fefde2fa677c48fd19b2f69cef71fac279bd02fac2753eeb7c060cf59ceff4fb3afc33098f031d9ebe729d2fc1b9f6047cc6e3e3847f773ce9f97f5e46fa0c88cfbd5d957e9fe3e38bcf77ed8376b0ed35c09a52db1dd8367f06e47658af81f20f614ce77aec077bcdece61ce1cf51c8eebeaed3795d01eaf47afadf17a5dbff550ecf2a87d91c93af419e3d099f01438dd5bd091e2d058fb80e7e3788df47f019b2bef79850f7f627bdc7f89e4189e3f35341e7d5fc6ceebc9aef3302d7e1d7e2678467609ccd7beabaf385fc7e99e67dc3f85d896668f7794fbb7d29fbd90abef5c1367e2ef86fb61de0b9a5f17744f0b982cc804b1f9499a100afabca00637506186b32c0589b01c6ba0c304ec800e3c40c304eca00e3fffddeb760c67c0618a76480b13e038c850c304ecd0063430618a76580717a06186764807166061867658071760618e76480716e0618e76580717e0618176480716106184fca00e3c919603c25038c8d19603c35038ca76580719132a6c2b82c2c6369ac8c8627d4ef1356f29b78e3f1fb842d9eb6025c172955da77bc5612e2f96995fe5e223314a2e37fff2b106369ac8c86a72d7d9e8a7f5fb30d3cf3fd0e6600c617f51b52929edb86f7a72f0fcb587a31cf960b715fe7589f1f86f7182c0fcbf8a29e7116e21e824a9f71e6bbe7617958c6d2581943ddcf8cdfe7180d0f7e3faec3e35900c6d25819437d0f02bfab351a9e4ef0ace4f12c006369ac8ca1ee99aaf49e3ebcb7bbd3e3992446e449fbf9a29d9eb6ba05f49d19b2c63829038c9333c098cf00e3940c30d66780b19001c6a919606cc800e3b40c304ecf00e38c0c30cecc00e3ac0c30cece00e39c0c30cecd00e3bc0c30cecf00e3820c302ecc00a3fe5da88cff6d46e4694c8f67d8fc07b615e27bad95f67d858727c5ef7d0eeb3bb615e0192715f71d9f059225c6ee0c30067e9e8dfaa88ccaa88c7a5eab8fe219d547f5511995511995f1a5ce9885315c1933918fa5b1321a9e95813ceba980672578c6af5b9e01c6151960ec0ecb581a2ba3e109f18ce13cb4311a9e5ef08c5fb73c2c6369ac8c8627c0f31063cf7a2be0c1e706f67a3c0bc0581a2ba3e1591dc8b35515f0ac06cf56793c0bc0581a2ba3e109f1ecc73cb4311a9e35e0d96a8f6701184b6365343c6bd3e7893d5b5301cf5af06c8dc7b3008ca5b1321a9e75e9f3c49eadad80671d78b6d6e35900c6d258190dcffaf47962cfd655c0b31e3c5be7f12c006369ac8c13414f9127f66c7d053c7de0d97a8f675219bb32c0d89d01c62cf8a88cca288951cf6bf55112a3faa83e2aa3322a637619576480518fb5324a65dc903e63a952c60dc0d3973e4f47a07ec6bfe37586dd578acf962819afce74bc5aef7855803a67807f6706f02f07edf2be799bdbab94f97401cc81da2ef1ef4baf77daeb76fc30cb59765d0b7a1778fa325be6dff0e3faf87b6e5ce712fb8329fcdba0bc54417fcf4abfbf1d239ddbdc1ef2ac11c6b340184faf309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34118cf22613c6b85f1ac12c63347184f8f309e69c2789609e3c90be3a915c6b35818cf5c613cd385f11485f14c11c6d3248ca74e184fab309e75c278560be399278c67a5309e19c2783a85f1d40be399208c67be309e99c2783a84f11484f1b409e399288ca745184f4e004f3e3afe9e853cfcff06d0aa9cd79af1b366dad0ff9f6df52a78cd39b65cedd9f7d9a0f1b5dd733caf459fce86bef4d972f1c52db14fd8561f6c737bf5c0718e109e16613c1385f1b409e32908e3e910c6335318cf7c613c1384f1d40be3e914c6334318cf4a613cf384f1ac16c6b34e184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d184f8f309e39c2785609e3592b8c6791309e0dc2786a84f1340be3992c8ca75d184f83309e92309ed9c278960ae359288ca75a18cf12613c9384f14c15c6334b184faf309e05c278d608e3a9f2f06c08c4c3d76f79dfbcbd4148db018e43fcbdf87303f569a3dd57addd2ff3737b3550e7b1baf2da7c7ec2d732977bbd1dff76d8081e6d0cd4173e1e39e7f8046ebb0bef2b88802172fc893c3c21eec708d4cf617998e2f3198ac6abf31cafdc6357803ae7827fe705f0cf97dbbccded29b3322731e3ef5b306b1eea750a6164edaca03c5dc54a7f83e33ce009f15e11c8f7781cdbe4f4a9d3e33bd7c15cdd14a09fbe7387b73779da6e8cd2f562f328bcd8ece1d93cce5e707b95329f9b4166f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466093e1b1e7ea606b3e6a15e8f1046d63686e589bf6fd4130d5f72ce761f943703cf7901fc09d4cff81ef2f39d3ef5787ce73a787e9d1fa09fbe7387b7cf87e35009f3a60c32abcf6363363cfc6c4466cd43bd954218593b2f2c4f3c8ead8c862f238d63e7034f88713e503fe3716c8bd3a7951edfb90e9e5f5b02f4d377eef0f616380ecaaccc3e66c3c3cf6860d63cd4eb15c2c8dae6a03ca5f8fb8dbdd1f065a4716c0bf08418e703f91e8f635b9d3ef57a7ce73a98ab5b03f4d377eef0f656380e95306fca20b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcf2f1d9f0d0fff7608b3e6a1de2a218cac9d1f94a733beeeb02a1abe8c74dd612bf06c499da77cdd2180eff175870b9c3eadf2f8ce75f0fcba20403f7de70e6f5f00c7e14467de944166cd8df161d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e6296901b8667b52d336b1eeaad16c2c8da96b03cf1730f5647c39791eedbb90078b606f027503fe3fb762e74fab4dae33bd7c1f3ebc200fdf49d3bbc7d211c076556661fb3e15963cbcc9a877a6b8430b2b6352c4f3c8ead89862f238d6317024f88713e503fe3716c9bd3a7351edfb90ee6eab600fdf49d3bbcbd0d8e83322bb38fd9f0acb56566cd43bdb5421859bb202c4f3c8ead8d862f238d63db8027c4381fa89ff138b6dde9d35a8fef5c0773757b807eface1ddede0ec7419995d9c76c78d6d932b3e6a1de3a218cace1e71f66fb4f7a3cdd0560a982b6428de191d3775e305f78d9208c6781309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34818cf1c613cd384f12c13c69317c6532b8c67b1309eb9c278a60be3290ae399228ca749184f9d309e56613cf384f1cc10c6532f8c6782309ef9c278660ae3e910c65310c6d3268c67a2309e16613c39013cf9e8f8eb9c78fda41a34be9eb10eb48b6c790368559e36783fdb41e3bfcf791f663c9e3aedf8f6aa3ced6df7708d879fd8561f6c737bf5c0b15d084f8b309e89c278da84f11484f17408e399298c67be309e09c278ea85f1cc10c6334f184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d18cf1c613c8b84f1d408e36916c63359184fbb309e06613c25613cb385f12c15c6b350184fb5309e25c2782609e3992a8c6796309e05c2783608e3a9f2f05c9c3e4ffc9d32ee7b045cb8f441f9e2c0fe04ea67d1ecf712bbaf14bfcb127f57ed52c7ab0d8e5705a87309f8776900ff72d02eef9bb7b93d6556e62466c3c373ab78bd94ebb50a61646d5b589e787c6c8d862f238d8f97024f8071ac23503fe3716c87d3a7568fef5c07737547807eface1ddedee169bb314ad78bcb46e1c5651e9ecbc6d90b6eaf52e64b32c82cc167c3c3f72a306b1eeab5086164ede2b03cf1f8d8120d5f461a1f2f039e10ef1f81fa198f09973b7d6af1f8ce75f0fcba3c403f7de70e6f5f0ec7a112e61d1964569fc7c66c78784e9b59f350af5908236b9706e529c5bf51d91c0d5f461ac72e079e10e37c20dfe371ec0aa74fcd1edfb90e9e5f5704e8a7efdce1ed2be03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66c3c3df4d63d63cd46b12c2c8da654179cad71d9aa2e1cb48d71dae009e10d76502f91e5f77b8d2e95393c777ae83b97a65807eface1ddebe128e83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66363c6db6ccac79a8d7268491b5cbc3f2c4dfdb6a8b862f235d77b81278425c9709d4cff8bac3554e9fda3cbe731dccd5ab02f4d377eef0f655701c9459997dcc86879fb5c5ac79a8d72e8491b52b82f294af9fb647c39791c6b1ab8027c4381fc8f7781cdbe9f4a9dde33bd7c15cdd19a09fbe7387b777c271a88479470699d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d7ee9f86c78f837b398350ff58a421859bb32284f677cdda1180d5f46baeeb01378425c9709e47b7cdde16aa74f458fef5c07cfafab03f4d377eef0f6d5701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961783ab83dbbce43bd0e218cac5d1596277eee4147347c19e9be9dab816767007f02f533be6f6797d3a70e8fef5c07cfaf5d01fae93b77787b171c875dcaaccc1e66c353b26566cd43bd921046d67686e589c7b152347c19691cdb053c21c6f940fd8cc7b1dd4e9f4a1edfb90ee6eaee00fdf49d3bbccded29b33227319bb6f7a4df763c1e60dbec4fe4f0f0b227b01781fa198f077b23bfc7dc5e01eae031df1ba09f396897f7cddb7be13854c2bc2383cceaf3d8984ddbfbd26f3b1e0fb06df627727878d917d88b40fd8cc783fec8ef31b757803a98a7fd01fa99837679dfbcdd0fc7a112e61d1964569fc7c66cdade9f7adbe5e7a461dbec4fe4f0f0b23fb01761fa591e0fae89fc1e737b05a883797a4d807ee6a05dde376f5f03c7419995599995599995599995599995599995599995599995599995599995599965339bb6af4dbdedf2fc3db6cdfe440e0f2fd706f6224c3fcbf3f70722bfc7dc5e01eae0313f10a09f396897f7cddb07e03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66d3f675e9b71d7f1f07db667f22878797eb027b11a89ff1fcfdf591df636eaf0075f0985f1fa09f396897f7cddbd7c371506665f6319bb60fa6de76f97a1eb6cdfe440e0f2f07037b11a69fe5f1e050e4f798db2b401d3ce68702f43307edf2be79fb101c874a98776490597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d5e7978ecfa6edc3a9b7dd19cfdf63dbec4fe4f0f07238b01761fa599ebf1f88fc1e737b05a883793a10a09f396897f7cddb03701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961da3e927edbf1f7d9b16df6277278783912d88b40fd8cef7fb921f27bcced15a00ee6e90d01fa99837679dfbc7d031c076556661f339e2713d36b3bbe1f8edba8b26ba31db5e56ad08ed9720d6883b65c0bda8db65c07da4db63c01b49ba13facdd62cbcb40bbd5964ba0bddc96af06ed15b6bc0bb457daf26ed05e65cb7b40bbcd96f782f66a5bde07daedb6dc0fda1db6bc1fb4d7d8f235a0bdd696af05ed75b67c00b4d7dbf275a0bdc196af07ed8db67c10b43b6df9106877d9f261d0de64cb03a0dd6dcb8b40bbc7a3bdd9962f01ed2d1eed5e5b9e04da7db63c19b4ff8132afdf6acb53407b9b2dd783f6765b2e80f60e5b9e0ada3b6db901b477d9f234d0eeb7e5e9a03d60cb33407bd0966782f6902dcf02ed615b9e0dda23b63c07b477dbf25cd01eb5e579a03d66cbf3417b8f2d2f00edbdb6bc10b4f7d9321ea3f7dbf211d0781cb801341e078e82c6e3c031d0781c18048dc7811b41e371e026d0781cb81934ce9d5b40e3dcb91534ce9d9783c6b9f30ad038775e091ae7ceab40e3dcb90d34ce9d5783c6b9733b689c3b7780c6b9f31ad038775e0b1ae7ceeb40e3dc793d689c3b6f008d73e78da071eedc091ae7ce5da071eebc0934ce9dbb413bc996ef01ed645b7e3368a7d8f25b406bb4e57b413bd596ef03ed345bc67181c79fb78276ba2dbf0db4c5b6fc76d096d8f23b405b6acbef048ddf73de055a932ddf0fda725b7e00b4665b7e10b4165b7e08b4565b7e18b4365b7e04b4765b7e3768455b7e14b40e5b7e0c347e9f7c0f689db6fc5ed0ba6cf97da075db328f0be6fc33e70cf799fda887fe357bb85933e73473f745e97e66e2b678dfbccded1946f69bff6f1c194ba3656c73180d4f2980679843bc8cf4b75f09783a02f004ea67fcb75fa7d3a7a2d3a702d4391dfad919a09f396897f7cddb9dd07688638e5ed4dafd2e76bca8813acfda3739b31ac947de87c9df764f5f5604ee0bef9bc7a515e3d07697d376abd3368ebdbc8c747e750173770066b3df9ef4f71b9f5f2bedbe38a7b89d56e8532f7890569fb0ed9c0d6e87f51a28ffbb61a82ed7633ff8fd8bd94d2ef3b14476f77525e77505a8b3c2d3ffbe28ddfef7383c3d0eb339262f340c7104381fe21c58e170f0762b78d793e0dd0af08eebe0fb5f7b20efba1d9e6ea76dc3c39f713a41e3cf0a3807c1ffdf3c0edceeb8d7e9e166ad0b187d9f75dad2671cf1b34e1b30b2d60d3c5d813c738ff562c71f7c5fae73eaf06b6ba04e95fd63af211afeb706d735e7ddbfa05ffc37f37fa274c7f4ba007ee1dff311f813391e46e017f7b33600cfe468e86ffa63830347775fd3bfad7ff7be1ca0d53898b8ce79ba51051a96ab3d5a140d9fbac0294f9ebac029cf2ac7169c32e1fae64f29d32d9e1ee83f7460f0e2c3fd87f71ebdf5c860ffbecd03d72075ad438fa4493d4052d47c3d1a897e5274fcc14ff5cc64b845b0ff9c05a9b69da8b540c6be89d1907d3cb363deadcd8862666acc19694e4e63ad996931332b6626c5cc9c9899123333626642cccc8799e930331b6626c3cc5c98998ac6a83c13711af07c1f18cd5f08e66c37330966e6c0cc14987709f3e9d38cace6938479d733239d19e1cca764f317931939cca86c461c334a98773df36e673e9d9877eb5514ab29d650aca55847b1de7abd81e20c8a3329cea27819c5d914e7509c4bb191e23c8a4d149b29cea7d842b195e2028a0b29b6516ca7b888e2e2a83cf3776954bec27919c5e51457505c497115c5cea83ca3be2b2acf989b197233236e66c0cd8cb799e13633da6606dbcc589b19eaeba3f20cb499713633cc6646d9cc269ad943335b686607cd6ca099fd33b37d6676cfcce699d93b335b6766e7cc6c9c997d33b36d6676edf6a83c7b6666cbccec98990d33b35f66b6cbcc6e99d92c337b6566abee8ecab35166f6c9cc3699d925339b64668fcc6c91991d32b34166f6c7ccf698d91d339b63666fcc6c8d999d31b33166f6c5ccb698d995c7a2f2ec89992d31b3236636e403141fa4f810c587293e42f1518a8f517c9ce2718a4f507c92e253149fa6f80cc567293e47f1798a2f507c91e24b145fa67882e22b145fa5f81ac5d729be41f14d8a6f517c9be23b14dfa5f85e54cec91f50fc90e2498a1f51fc98e227143fa5f819c5cf297e41f14b8aa7287e45f16b8adf503c4df10cc5b314cf51fc96e27714cf53fc9ee20f147fa4f813c59f295ea0f80bc55f29fe46f1778a7f50fc331a9a49c581e209bbc1b37abb0707fb0f1d196c1c1c683c74e3c1c103470ededa78f381c16b1b076eea3fbaffe0c0cdf8e2ebec30c453961b8e1edd7d6be381c3fbfa6f691cb871b071607fe39e811b0fef3b862fbad3be68e1f12deedeb72fb9b1fbab5e04e9c3636cf423f6753c19bc71e4be7d7c2c867c662c2f7a7a8c1dbad8be8bacb1dbdbcbefd48dc70e0e0c36161b0fd3bfbb0fd26bfaf7b535e2ff1d23938f0d361e1bdc7d74b071ffd181438d1d6db8df47ebc6d089671ac6f0a2dcb4d1f73cfa5f16540aa2d9140300", "isInternal": false } ], - "packedBytecode": "0x000000028df71de50000003d241f8b08000000000000ffed9d079c1545beef7b8621e87146cc028651519078e630648483398b2092c330e41c86282819441104910c43ce8860d8e866379936e8aebb77f7eedebcf7ed0b9ff73ef7bef7ee7d6fefeb3aa7fe6f7e14d5e39cb16bfc8d547f3e35a7fa37d55ddffa757575a8eeaebc203bfd290c793ade200c2d830b27f97f5aff263fdf5412e3ba922e39f3ea09677e3de16c504f380bea0967c37ac2d9a89e7036ae279c4dea09e725f584f3d27ac299a8279c97d513cec27ac259544f382faf279c4deb09e715f584f3ca7ac279553de1bcba9e705e534f38afad279cd7d513ceebeb0967b37ac2d9bc9e70b6a8279c37d413ce1beb09e74df584f3e67ac2595c4f386fa9279cb7d613cedb62e46c0b9c72cffe76fd7b87fe6da57f5bebdf3bf56f1bfddb5697b140cfb70b43fb3074084347e37fca1875e33e15864ec6ff4ac3d0390c5dc2d055ffaf58ffaf5b18ba87a147187a86a15718ee0a43ef30f4d17ef40dc3dd61b8270cf786e1be30dc1f8607c2f060181e0ac3c36178240c8f86e1b1303c1e8627c2d02f0c4f86a17f180684e1a9300c0cc3d3611864b00c0ec390300c0dc3b0300c0fc388308c0cc3a8308c0e435918c684a13c0c63c3302e0ce3c330210c13c330290c93c330250c53c3302d0cd3c330230c33c3302b0cb3c330270c1561981b867961986f78b6200c0bc3b0280ccf189c8bc3b0240ccf86e1b9302c0dc3b2302c0fc38a30ac0cc3aa30ac0ec39a30ac0dc3f36158178617c2f06218d687e1a5306c08c3c630bc1c864d61d81c8657c2b0250caf86616b18b685617b18768461a766911d6157187687614f18f686a1320cfbc2b03f0c07c270300c87c270380c47c270340cc7c2703c0c27c270320ca7c2703a0caf85e14c185e0fc3d9309c0bc31b6178330c6f85e1ed307c250c5f0dc3d7c2f0f5307c230cdf0cc33b61f85618be1d86ef84e1bb61f85e18be1f861f84e1dd30fc300c3f0ac38fc3f09330fcd4f0fcbd30bc1f860fc2f0a1d63ed2bf3fd3bf3fd7bfbfd0bfbfd4bf1febdf4ff4efaff4efaff5efa7faf737faf7b7faf7aff4efeff4efeff5ef5febdf3fe8df3feadfbfd1bf7fab7fff4efffebdfefd07fdfb8ffaf79ff4afeac75bde221b6f12544de920a636a7745c99ba8f2f669afd84aa0faa81fe9ffc166bbd40cfcb6f9ed61beaf98686de48cf3732d6d344cf3731f4223d5f64e84df57c5343bf52cf5f69e857ebf9ab0dfd163d7f0be809fdbf6cc1b23f4a6ba0a53cd0a4fee583d6506b0d406b24ab03adb1d61a8226dbb711689768ad3168976aad096809ad5d02da655abb14b442ad25402bd2da65a05daeb542d09a6aad08b42bb4763968576aad29685769ed0ad0aed6da95a05da3b5ab40bb566b5783769dd6ae01ed7aad5d0b5a33ad5d075a73ad5d0f9adec58266a0dda0b5e6a0dda8b516a0dda4b51b40bb596b378256acb59b40bb456b378376abd68a41bb4d6bb780d6526bb78226e70ab7694dd53369fb32cb683d1fb4db65ff06ed0ed9b7416b25fb3568ad659f06ed4ec85bb436b28f83d6566b52c7d5ffbae8783a88ab7d4b95abf5768d7bbde19ad57abbc7bfdea46a2f7b04555ea7219faee0554f1d8ff1798612cc3b4f07c947f402883f0069259df821ed94b0abb6a79b8ef7ac66b92ec6724590a69ba5fce920def2773778ba1bcc6a9bf4028ef8eb6ca7a4afb3359e72aeb30321ad59f7e498f965acb30f0387833a5beaeb6c8da79ceb6c39a435eb9e9cbf7d19ebec60e0705067bbb9a9b3a9a4afb3d97b264160af7b722df165acb3e38123fe3adbd9d7d99a4f39d7d9e720ad59f7e4baf6cb58672b8023fe3adbb59b3f37a8f194739d5d0f69cdba27f758be8c7576397038a8b3e5be9dadf194739ddd0969cdba27f7fbbe8c75762370c45f67bb3baab39d7c9d0db2fd5f4160af7b72eff9cb5867f70047fc75b6dcdf9fadf994739d7d1bd29a754ffa41be8c75f6a48eab7e868f743fc30da0fd4c6b3782f673addd04da2fb4763368bf84fe42d13e96be44d03ed1daada0fd4a6bb781f66ba3ef55699f6aed76d07ea3b53b40fbadd65a81f6575a6b0ddaefb4762768bfd75a1bd0fe5a6b6d41fb83d6da81f647adb507ed6fb4d601b4bfd55a47d0fe4e6b49d0fe5e6b25a0fd83d652a0fda3d63a81f64f5a2b05ed4f5aebac35d54f297d5fef6aad0970a583f8ea68023c9029cf984f43bca35b9e6411f0605e25f1e7d54995fdbc87ad3ea3ec25c0937250f604e451139e14f0748a9f27f38e5f69fcebcd6ce3a4e16902f24a42b93a3b28571ee425eb9679c9af0834dca73b5b18633fcf082fbcf2202f59b7cc770146d1b08d913657f61f758cf967e075b02f65ce33243f797759384a409734d7b7a862fb2f5a2b84ff637bdbc9d01cd5cb4cbd90bc64dd325f0a8c529e4e75cf98aa2963ca6074d546e4415eb26e9f77d576907807e0e9e688c76cd324ef6e7590771723ef12236f6c3b65aaeed8d605981d5c6f957c11d75b78fec070bd75455e555af3ba49dae15cafb73a1bcb315e6f35caabe270b03f64ea40378343e64bc0bbee11de7503ef24cdede09d8373cf8c775d0d1e994f018fb463a5c0d3a18e793a10e48de7b0b2ddf05a0acf035c6daf0e06a3ccdbb65717604c59181d9c13a6aa3b469600a368783f2ae9c8b3a8ed9a24c9dbc57525be4b21e7e6e6b54d01a4f93ff9d95fd556b6cf73ca96c27367996a7acd1bff764a2571ffa8098fe37da8c4517d4ce2fd9bbf04f1d635b35d32db9ba87b3caedaf2a4c123f3929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c523fd09f8dc96a4eb44c2683effe6ea3e7fe65b28b22efdabfa75de817e9df8fb2d5249ecfb93e7205a19652e80341fe555a5fdae8eab670ea49f0a9fb5329fbf72d96787cf63a6615ef2c367ad705b323cef541c5bded9efd2b8e86fbb3cc87e53c77cf6b393c55317cf3fa3a77986a7f81cf89d068faaa7ff915fc5e6a2ef2fd7be48f44ae271f6ed1505f6ba1eff76499dd7679d1f9cdf7ee071c6d5f33bd2564b7f793723ef0248f37b788e4a9ead92718692c672f8dc8fac5b9669057a7763dd4df5b2c2d1d0587f292c2b69fe086dea4aa8ab0edaca54aecfae63bf79fcc7e16c3f7e32079e0ec0e3a29d7174be91c47d20ee7e7cf3f934db798ca4c167fb1c3c5759edf34e929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c563f6b5e2fbb525248ca2397ef621d39fd15aaf4bd6affa7566e757e5ebba1f4efa9c5a1b65c67747cfe557a59da7e385c185cf3b446d4b57dfa788da96921f7e7ba603f0b8e8d7cd83bc64dd1d2d5e48bc38b6bcb3fdf8f17b5cd58f9f347c2db178ea6a7fc53e56f414f7d794c1837da351dff6e968688ef6f16aeb85e487fb5247d0248eef47bbd8ce782c319feb91fcb0fffa25ed6dd3c0d5b64f255db61bf8dd94747061fdc6efa96c86b66f8b8ee3331cf8ecc841cbff65aaae9f5afc5365ee157f9933dbf72ee04c433e98776f608d29ef12cc3b4f07c947f402881fc8af4a2be9c40ff15ad8d53e22df80417673b994b15c11a4e969297f3a88b7fcbd0c9e5e06b3da26dba09e1d84e3bfab36a9678447adc0234983e741ae9ec933db48f3f9467c6eaf919106cf5924cd4968a354596ccf8fda9e3974751c8b7ae6d0766edc0118cd329acf795eeccf697d03da8bb89fd3fa06d4217c4e2b30d6df1ad62f5c8d82e8638ba4f9b6b17ef39c5c96c1e7c024cdf7a0bdf8975a9c937f51d757b673725c2eaaec8a19bf83968e9119eb04b2e07982a479dfd866dd23b8bb5896fd286259f1cafc56586170a17f6ebeb396dde77b1965917add13ca22693e31ce01e33f6fc99e03bafaa61c9e7ba8f576b49455d2fc16f6b5dfc1399e6c27dc6fff6cf9bf4cd59d03e2788e7de22f7312f719d9be7d2c79f705d698f22ec175c939605fc3830288ff2768d3259da415af855ded23721e85ece672dd8ce58a204d6f4bf9d341bce5ef63f0f43198d536f903d4b33fc339a0abb6ba778447adc1234983f7146ddf01b5ddeba8ab7345f3fbc245c185f709f038e9e6bcc9fe9e90795fcd768ed0dae0c773847f83763661496bde2f94e3659ccf0de3bb12a590ef7f58f24dc7ec6757f02d0df3785ef045e6ede03be1997744f0bb82c280531ae2f8ed70592e1f185d7c6f3d119cff7de0cf62c46fb0cb720d80d1c536ccf5fbc4a5c028cb1500a38bf7bff01bf93561ec048cb82f0aa38bef92d6f67b8e78dddd081899deabc2fbc78d81d1c5b1abb6efd3e031b709fcba1a3b24990363476094e52e014617f7aff07ca3268c78ee22cb5d0a8c2eee33e73a060b7e1f1aefff08a38b73c05caf51f05e952c771930f670c4d83d07c61ec088f71c84d1c5f56402f2ad09634f60445e6174d0079061ec990323de2b97e52e07c6bb1c31f6ca81f12e6094e59a02a38bfbf909c8b7268cbd815196bb02181d5ceb67187be7c088d7c4b2dc95c09876c4d82707c63430ca725701a38bebf684c1f0598c7d8151f4ab81f16e478c7d7360bc1b1865b96b80f11e478c77e7c0780f30ca72d702e3bd8e18efc981f15e6094e5ae03c6fb1c31de9b03e37dc028cb5d0f8cf73b62bc2f07c6fb8151966b068c0f3862bc3f07c6078051966b0e8c0f3a627c2007c6078151966b018c0f39627c3007c687805196bb01181f76c4f8500e8c0f03a32c7723303ee288f1e11c181f014659ee26607cd411e32339303e0a8cb2dccdc0f89823c64773607c0c1865b962607cdc11e36339303e0e8cb2dc2dc0f88423c6c773607c021865b95b81b19f23c6277260ec078cb2dc6dc0f8a423c67e39303e098cfd2c8cfd1d313e9903637f6094e5ee04c601f13366be43d33f07c601c0f354fc3c19cf06e4c0f3945b9ecc379c0658f27a3afebc32db626050f3b23f0d3c83e2e7c96c8ba773e0118622580e3d1b1c3f63c6b34139300e069e21f1f3643c1b9c03cf10f06cb0c5b3a1f133663c1b9203e350e019163f4fc6b3a139f00c03cf865a3c1b1e3f63c6b36139300e079e11f1f3643c1b9e03cf08f06cb8c5b391f133663c1b9103e348e019153f4fc6b39139f08c02cf465a3c1b1d3f63c6b35139308e069eb2f879329e8dce81a70c3c1b6df16c4cfc8c19cfca72601c033ce5f1f3643c1b93034f397836c6e2d9d8f819339e95e7c0381678c6c5cf93f16c6c0e3ce3c0b3b116cfc63b621c9703e3780b4fdcdf171d67c96ba2a3b24f086a5e76612882e590719223c68939304e0246590efbd7273b629c9403e3646094e5b07f7d8a23c6c939304e0146590efbd7a73a629c9203e3546094e5b07f7d9a23c6a939304e0346590efbd7a73b629c9603e37460445e619ce188717a0e8c33804b96c3fef5998e1867e4c03813186539ec5f9fe58871660e8cb3805196c3fef5d98e1867e5c0381b186539ec5f9fe38871760e8c73805196c3fef50a478c737260ac0046590efbd7e73a62acc881712e30ca72d8bf3ecf11e3dc1c18e701a32c87fdebf31d31cecb81713e30ca72d8bfbec011e3fc1c181700a32c87fdeb0b1d312ec881712130ca72d8bfbec811e3c21c181701a32c87fdebcf38625c9403e333c028cb61fffa62478ccfe4c0b818186539ec5f5fe28871710e8c4b805196c36bae671d312ec981f159605ce2192f0a46e4298e8f278965c7bc9e2328fb73169ebcc04dd931afa504655faa7feb1be3b3f580717c3d60f43e7a46cff8e563f4fbb5f79189d1fbe87df48c9ed1337ac68b9db13eb4e19eb15ed4c7546d1915cfb2f879329e2dcd8167197826cb3de59631555b46c5b33c7e9e8c67cb72e0590e9e2db378e68031555b46c5b3227e9e8c67cb73e059019e2db778e68031555b46c5b3327e9e8c672b72e059099eadb078e68031555b46c5b32a7e9e8c672b73e059059eadb478e68031555b46c5b33a7e9e8c67ab72e0590d9eadb278e68031555b46c5b3267e9e8c67ab73e059039eadb678e68031555b46c5b3367e9e8c676b72e0590b9eadb178e68031555b46c5f37cfc3c19cfd6e6c0f33c78b6d6e2192be3f87ac0f86c3d60ac0f3e7a46cfc8c4e8f76bef2313a3f7d1fbe8193da367acbf8ccfd50346bfad3d232be3baf81953b932ae73ec99a37266c69f7a41af2bc66f22a494572f1a5ead35bc2a82342f807f2f3af02f0ff29575cbbce4972b734b02664779a7645ce4b5467ecf1a7ea869bdfe6d08fa78f0f4251d97b1e724fd73a04b9a597aa00f19d352261c93717dfce52da96edf96fc90672e194f67329e19643cabc9782691f1ac20e31943c6b3948c673819cfd3643c4f90f1b422e3b9878ca73d194f03329e0e643ca5643c7791f13c44c633998c6726194f3919cf3c329e11643cadc9780691f12c26e3e947c6f33019cfbd643cbdc978ba91f1b421e3e944c6338b8c673e19cf14329e95643c63c9789691f18c24e35943c633988ce749329e47c878ee23e3694bc6d39d8ca70f194f8a8c6736194f3b329ea9643c0bc878c691f18c22e36949c633848ca73f19cfa3643cf793f1a4c9787a90f12c24e32921e39943c6d3958c671a19cf2a329e3bc8782690f18c26e35942c6733b19cf50329e01643ccbc9781e23e379808ca72f194f4f329e45643c49329e0a329e2e643cd3c9782692f19491f10c23e31948c6f33819cf3a329e07c978ee26e3e945c6f30c194f1e014f22b8f09dd404fc7f1d68f9c6b28dc330ac45d5ff37683d1f96d9a8e30d2cebde00da4b3abed1b22cfab401ca92d6f1e4e79b323e615e699897fc0a81632309cf33643cbdc878ee26e379908c671d19cfe3643c03c9788691f19491f14c24e3994ec6d3858ca7828c2749c6b3888ca727194f5f329e07c8781e23e3594ec633808c672819cfed643c4bc8784693f14c20e3b9838c671519cf34329eae643c73c8784ac8781692f1f420e34993f1dc4fc6f328194f7f329e21643c2dc9784691f18c23e35940c633958ca71d19cf6c329e14194f1f329eee643c6dc978ee23e379848ce749329ec1643c6bc8784692f12c23e3194bc6b3928c670a19cf7c329e59643c9dc878da90f17423e3e94dc6732f19cfc3643cfdc8781693f10c22e3694dc633828c671e194f3919cf4c329ec9643c0f91f1dc45c6534ac6d3818ca701194f7b329e7bc8785a91f13c41c6f33419cf70329ea5643c63c8785690f14c22e3594dc633838ca73319cf5c329e8e161e07e33b6678e4fd3c59b7ccaf23c9dbc176c88c6bf9b2a3326dd2eb6aa8d72bfc925f01a4f9b071f6b76990ad0fa20bd77a1dc7ba21de6c028f36392a8b6c8f3c63fb38ce3b85ef8d06c01018fe04161e17efdb3a2ae779f530eef155371b5e99dbae08d2bc0cfe6d76e09fad6ecbbce4972b734b0266ac17c541bcf5e295f8cbf4ffc76d155f5f31fcc572bdaae331d6cba45ac716bdae8690dfab90ef361dcf8b315fb5aead7a5d32ceac706c035dd2fc33b4cbc8ac26697ff19b66db753c1d1f73661c6c1c47573cc1290df1edc0b3d5018fa37266b6cd0ea34ceb8c3215419a2d50ce1d0eca9907f9caba657e07f0c8d411785cd4839a6cf3a8b18719783a93f1cc20e3594dc633898c670519cf18329ea5643cc3c9789e26e379828ca71519cf3d643cedc9781a90f17420e32925e3b98b8ce721329ec9643c33c978cac978e691f18c20e3694dc633888c673119cf16329e7e643c0f93f1dc4bc6d39b8ca71b194f1b329e4e643cb3c878e693f14c21e35949c633968c671919cf48329e35643c83c9789e24e379848ce73e329eb6643cddc978fa90f1a4c8786693f1b423e3994ac6b3808c671c19cf28329e96643c43c878fa93f13c4ac6733f194f9a8ca70719cf42329e12329e39643c5dc978a691f1ac22e3b9838c670219cf68329e25643c43c9780690f12c27e3d94cc6f31819cf03643c7dc9787a92f12c22e34992f15490f17421e3994ec633918ca78c8c671819cf40329ec7c9781e24e3b99b8ca71719cf33643c79043c51630fcbff378326efd4e178c43b757c2b68f9963ce459f81da015e8b8ac43bdca39bec585eb469f5cbd478879a5615ef2c3b1877792f03c43c6d38b8ce76e329e07c9781e27e31948c6338c8ca78c8c672219cf74329e2e643c15643c49329e45643c3dc978fa92f13c40c6f31819cf66329ee5643c03c8788692f12c21e3194dc633818ce70e329e55643cd3c878ba92f1cc21e32921e35948c6d3838c274dc6733f19cfa3643cfdc9788690f1b424e31945c6338e8c670119cf54329e76643cb3c97852643c7dc878ba93f1b425e3b98f8ce711329e27c9780693f1ac21e31949c6b38c8c672c19cf4a329e29643cf3c9786691f17422e36943c6d38d8ca73719cfbd643c0f93f1f423e3d942c6b3988c6710194f6b329e11643cf3c878cac9786692f14c26e379888ce72e329e52329e0e643c0dc878da93f1dc43c6d38a8ce709329ea7c9788693f12c25e31943c6b3828c671219cf6a329e19643c9dc978e692f174ac1b9e52f52e1e8ef7295c38a521be0378b638f0c7513993f81e669c63692aaf76195e6d36bc2a8234dbc1bf5d0efccb837c65dd322ff97966cf1cc5ac78e4d970dbfbc14b481845dbe294a734998032cb545dfbb80b785c1c3f1cf99e69c7761b655a62f15dd2605dddeda09cb67d47e6775bf22e0ee2f5624f0dbcd863e1d953c75e487eb9326faf87ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e0781f7d9fbec7d4e7ebec9fbace3de67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e473133f8ac7896eab8b02620dd521246d176b8e5c9bc6fb434387fca33e6d310df033cbb1cf8e3a89c9967c8f71a655a1a5ce8bba4c1fd6baf8372daf61d99df0bdb2117e6ddf590d9fb5c3b66c5b34cc797eadf04a45b46c228da2eb73c99766c5970fe545d3bb617785cb4f38eca9969c72a8d322db3f82e6970ffaa74504edbbe23f395b01d2a3db367b6302b9ee53a2eac0948b79c8451b43d4e795299f71b9707e74fd5b56395c0e3a29d77e47ba61ddb679469b9c577498375759f8372daf61d9997fc7265de5d0f99bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866eff3c5e3b3e2916f260b6b02d2ad2061146daf539e4e997e8715c1f9539e319f86f83ee0a98c9d27dbefe0c0f74cbfc37ea34c2b2cbe4b1adcbff63b28a76ddf91f9fdb01dbeecccbbeb21b3af1b75c3eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c73143343dd503c2b755c5813906e2509a368956e7932df3d58199c3fe519f36988ef079e7d0efc7154cecc733b078c32adb4f82e6970ff3ae0a09cb67d47e60fc076f0cc9ed9c6ac7856e9b8b02620dd2a1246d1f6b9e5c9b463ab82f3a7eadab103c0e3a29d7754ce4c3b76d028d32a8bef9206ebea4107e5b4ed3b327f10b68367f6cc3666c5b35ac7853501e95693308ab6df2d4fa61d5b1d9c3f55d78e1d041e17edbca37266dab1434699565b7c973458570f3928a76ddf91f943b01d3cb367b6312b9e353a2eac0948b7868451b4036e7932edd89ae0fca9ba76ec10f0b868e71d9533d38e1d36cab4c6e2bba4c1ba7ad841396dfb8ecc1f86ede0993db38d59f1f4d771614d40bafe248ca2e1f9cf91f8794a13068f9aaa6bc78e38f6c7513933edd8d1c0eefb11f05dd2605d3deaa09c7990afac5be68fc276c88579773d64f63ed78e59f10cd471614d40ba81248ca21d069e63f1f394260c1e3555d78e1d73ec8fa37266dab1e381ddf763e0bba4c1fdebb88372e641beb26e993f0edb2117e6ddf590d9fb5c3b66c53348c7853501e90691308a7614784ec4ce93fdbe31f2a8a9ba76ec84637fdc9433db8e9d0cecbe9f00df250dee5f271d94330ff29575cbfc49d80e9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99b99915cf101d17d604a41b42c228da71e039153b4fb6df0179d4545dbfc329c7feb82967b6dfe17460f7fd14f82e69b0ae9e7650ce3cc857d62df3a7613b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563cc3745c5813906e1809a3682781e7b5f8794a13068f9aaaeb7778cdb13f8eca99e9773813d87d7f0d7c97345857cf3828671ee42beb96f933b01d3cb367b6312b9e113a2eac094837828451b4d3c0f37aec3cd9fe53e4515375edd8eb8efd7153ce6c3b7636b0fbfe3af82e69b0ae9e7550ce3cc857d62df367613be4c2bcbb1e327b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccdee78bc767c5334ac7853501e94691308a760678cec5ced329993078d4545dbfc339c7feb82967b6dfe18dc0eefb39f05dd2e0fef5868372e641beb26e997f03b6c3979d79773d64f675a36e987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e6266a81b8aa74cc7853501e9ca4818453b0b3c6fc6cf539a3078d454dd733b6f3af6c7513933cfedbc15d87d7f137c9734b87fbde5a09c7990afac5be6df82ede0993db38d59f194ebb8b026205d3909a3686fb8e549250c1e3555d78ebd053c5f899f27d3aebe9503cf5780e7edf8794a1c9533a9d6fb55608f6bbdcaabaf195ebd657855046990e16b0efccb837c65dd322ff97966cf1cc58c6da1b02620dd9b248ca2bd0d3c2eda0d55f6367a5db2fe8661e8d7b42adf73f1e75b8ad72c0df57a8543f22b8034e9e655699fd26c85f07fd96eaa3c670dcdd1b76f4a6cef4bc8bce45718d4d93544b5d734e8858be7fc733dee9fb5f0fc253e9e24eee798978b6f2be5facec5190b4f8c652f897adfc4c577ec54d9dbea75c9fad53e3ab1a953cf4b71df93f6a3ad51e602487303b41f53a1fdb0b515aef7cdbcc0be6fe60755ed9970156bddbc37f117ad4bba73901edb9cfefa17f7cffe505657ed62d43509b68b66dbedd27bf3fe98997711f8728ed433db751cfa38d0c23d90801beb635dee67b26edb3d8481868f6c9ee1b63e67f17190857b100137e37e3dc8f091cdb3cfdaaf8758b887107033eed7430c1fd93cfbacfd7a98857b180137e37e3dccf091cdb3cfdaaf4758b847107033eed7230c1fd93cfbacfd7a94857b140137e37e3dcaf091cdb3cfdaafcb2cdc6504dc8cfb7599e1239b679fb55f975bb8cb09b819f7eb9af69332edd78eee7f67fa49d133355577cff09c537fb2dfabcfe5f993d781c7459d72540f928eeeb966fa49cdf107ce195ee1f8038eefcb56fb5d22c9cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f33bedf8bfd2b92ee0d1246d11c3f9b9fe9cf68a7d725eb57cffeceb8c265bea924f67bca73c9264701a4f9d3f55569e76836ec5fc47ed13386e6725b9ae34fcbbce45708e5c1faefea5deda8baf58625efe2d8f24e95bbf13895bc3c5cc72541d5767ecd280f7a7a3af6fccff734cff0f4b4e3bc737d5f02791cf4c596382a67a62d386594c9f4b808d2b484729e7250ce3cc857d62df3a78047a67ce0715507038327b0f823d35c329ece643c93c8788693f1dc42c6f30419cf35643cf790f15c42c6b3988ca703194f7b329e99643ce5643c83c8786e20e379988ca729194f6f329e02329ef9643c9dc878da90f1d4c53d805c78a690f18c24e3b98d8ce749329e3bc978ae23e3b98f8c2741c6d3968ca73b19cf6c329e71643c43c8786e22e379948ce74a329e34194f23329e85643c25643cd3c878ee20e3194dc673968ce776329e01643ccdc8781e20e32924e3e949c65341c6d3858c672219cf30329e62329ec7c978ae26e3b99b8ca70919cf33643c1dc9786690f18c21e3799a8ca70519cf43643cadc8782e27e3b98b8ca70119cf3c329e52329ec9643c23c8785a93f1dc4ac6d38f8ce75a329e7bc9782e25e3e946c6338b8c672c19cf60329e1bc9781e21e3b9828ca70f194f43329e05643c29329e76643c53c9784691f1b424e3e94fc6733d19cffd643c9791f1f420e39943c6d3958c670219cf50329e9bc9781e23e3b98a8ca72f194f63329e45643c49329ee9643c65643c03c9789a93f13c48c65344c6d38b8c278f8027115cf82d9d04fcff75d0e49b2ff8bdb07ccbfaa49f51d2abe3d0cc1617ae3bdfb2eed31606f4e9249425ade3c9cf379df79d9b3cbd5e9997fc0a81e334094f2f329e22329e07c9789a93f10c24e32923e3994ec69324e35944c6d3988ca72f19cf55643c8f91f1dc4cc633948c6702194f57329e39643c3dc8782e23e3b99f8ce77a329efe643c2dc9784691f14c25e36947c69322e35940c6d3908ca70f19cf15643c8f90f1dc48c633988c672c19cf2c329e6e643c9792f1dc4bc6732d194f3f329e5bc9785a93f18c20e3994cc6534ac6338f8ca70119cf5d643c9793f1b422e379888ca70519cfd3643c63c8786690f17424e379868ca70919cfdd643c5793f13c4ec6534cc6338c8c6722194f17329e0a329e9e643c85643c0f90f13423e31940c6733b19cf59329ed1643c7790f14c23e32921e35948c6d3888c274dc6732519cfa3643c3791f10c21e31947c6339b8ca73b194f5b329e0419cf7d643cd791f1dc49c6f32419cf6d643c23c978a690f19c21e36943c6d3898c673e194f01194f6f329ea6643c0f93f1dc40c633888ca79c8c6726194f7b329e0e643c8bc9782e21e3b9878ce71a329e27c8786e21e3194ec633898ca73319cf5c329e7c8307ffafde3592ebb353fab700febf583f8cd254af4bd2c83b89eaded2094353e53deea8bc2782aa290df3c7a1bcc27e02784e38e23969f0987917427c207876ccd014e351478cc70c46993f0a8ce2df31e039e688e7b8c163e65d08f141e0d91143538c871d311e311865fe30308a7f4780e788239ea3068f997721c4878067870c4d311e74c478c86094f983c028fe1d029e438e780e1b3c66de85101f069e1d3034c5b8df11e3018351e6f703a3f87700780e38e23968f0987917427c0478b6cfd01463a523c67d06a3cc5702a3f8b70f78f639e2d96ff0987917427c1478b6d7d014e31e478c7b0d4699df038c953abe1778f63ae2a93478ccbc0b215e069eed3634c5b8cb11e36e8351e67701a3f8b71b78763be2d963f098791742bc1c3cdb69688a718723c69d06a3ccef0046f16f27f0ec74c4b3cbe031f32e84783fd084b72b68db75bc0b68db74bc33685b75bc14b45775bc13685b743c05da2b3a5e02da66f103b44d3ade11b49775bc03681b75bc1b681b74bc3b682fe9780fd0d6eb784fd05ed4f15ea0bda0e37781b64ec77b83f6bc8ef7016dad8ea7415ba3e37d415bade37783b64ac7ef016da58edf0bda0a1dbf0fb4e53a7e3f68cb74fc01d096eaf883a03da7e30f81f6ac8e3f0cda121d7f04b4f13afe28684fe9f863a0bda9e38f83f6968e3f01dadb3afe24685fd1f101a07d55c79f06ed6b3a3e18b4afebf850d0bea1e3c341fba68e8f04ed1d1d1f0ddab7747c0c68dfd6f1b1a07d47c7c781f65d1d9f00daf7747c2268dfd7f149a0fd40c72783f6ae8e4f01ed873a3e15b41fe9f834d07eace3d341fb898ecf00eda73a3e13b4f7747c1668efebf86cd03ed0f139a07da8e315a07da4e37341fb998ecf03ede73a3e1fb45fe8f802d07ea9e30b41fb58c71781f6898e3f03daaf747c3168bfd6711cf7ee373a5e1cc4dbbe7f1a544dc590b7e4a7d2fc56c71b196964d90248d350df1c55f73b8a82aaf65f8e074a93f67f3b68d2fe6f034ddaffada049fbff2a68d2fe6f014ddaff574093f67f3368d2fe6f024ddaff974193f67f2368d2fe6f004ddaff974093f67f3d68d2febf089ab4ff2f8026edff3ad0a4fd7f1eb4b48eaf054ddaff35a049fbbf1a3469ff578126edff4ad0a4fd5f019ab4ffcb4193f67f1968d2fe2f054ddaffe74093f6ff59d0a4fd5f029ab4ffe34193f6ff29d0a4fd7f133469ffdf024df6b54f419363c2dba0c931e12ba0c931e1aba0c931e16ba0c931e1eba0c931e11ba0c931e19ba08dd6f177409363c2b7409363c2b7419363c277409363c277419363c2f7409363c2f7419363c20f409363c2bba0c931e187a0c931e147a04dd7f11f8326c7849f8026c7849f8226c784f7409363c2fba0c931e103d0e498f02168724cf808343926fc0c343926fc1c343926fc02343926fc123439267c0c9a1c133e014d8e09728c68029adcaf5653f2734e4541d5940f7909533a88f79883531ae2cf40d9655a43c6730b19cf66329e6bc8782e21e3694fc6534ec6b3948c671019cf8b643c3790f17c4ac6b38d8ca72919cf21329e83643c05643c6dc878ce90f1ec24e3798b8c671519cf6d643c7792f15c47c6f332194f828ca72d19cf10329e75643c3791f1bc4ac6732519cf01329efd643c8dc878de26e3b9838c670519cf59329edbc9783690f13423e32924e31946c6b3968ca7988ce715329eabc978f691f15492f13421e33945c673928c671919cf7a329e16643cadc8782e27e3d94ec6d3808c6704194f6b329e5bc9785693f16c22e3b9968c672f19cf1e329e4bc9784e90f11c27e379818ce746329ead643c5790f13424e36947c6338a8c6725194f7f329e8d643cd793f1ec26e3d945c6731919cf31329ea3643ccf93f1dc4cc6b3858ce72a329ec6643c65643ccbc9780692f1bc44c6d39c8ce757643c3bc8788ac8788e90f11c26e3c923e0490047009afcbf0168f2beee59d0e4bdde33a0c93bbf3b419377821783b6d0a2e55bf884e113d0e45d918f4193fb0f8b409367f47e099a1ca7257f35bfa0c585fcf9967236b0f02fb294f363cbb2b8bd65997410eff6c6bcd281fddb1c7906e317cd73988ce708194f1119cf0e329e5f91f13427e379898c672019cf72329e32329ec6643c5791f16c21e3b9998ce779329ea3643cc7c8782e23e3d945c6b39b8ce77a329e8d643cfdc9785692f18c22e36947c6d3908ce70a329ead643c3792f1bc40c6739c8ce70419cfa5643c7bc878f692f15c4bc6b3898c673519cfad643cadc9784690f13420e3d94ec67339194f2b329e16643cebc9789691f19c24e33945c6d3848ca7928c671f19cfd5643caf90f11493f1ac25e31946c65348c6d38c8c670319cfed643c67c9785690f1dc41c6f336194f23329efd643c07c878ae24e379958ce726329e75643c43c878da92f124c8785e26e3b98e8ce74e329edbc8785691f1bc45c6b3938ce70c194f1b329e02329e83643c87c8789a92f16c23e3f9948ce706329e17c9780691f12c25e32927e3694fc6730919cf35643c9bc9786e21e35943c6936fe139eb8847fab265dd327ff64b9ef77123efe31749de478dbc8f5e24791f36f23e7c91e47dd0c8fbe04592f77e23effd1749de9546de951749de7b8cbcf75c2479ef32f2de7591e4cd7cdea2be47d15fc74fe9df04fc1fbfe379c611e3598351e6cf00a368380e477f473c51e73cfd09f2565e0cd47179d72601ff1f088caeea547f8351e66d750abf8b3dd0114fd4b9da4082bc951772cf48de0d4fc0ff0701a3ab3a35d06094795b9d3a0a3c831cf1449d630e22c85b79217de4f2eda004fc1fc7857555a706198c326fab53f81db4218e78a2ce8d8710e4adbc90673aa5ef2301ff1f068caeead4108351e66d75ea20f00c73c413754e3f8c206fe585bc1325cf5625e0ff38ce8dab3a35cc6094795b9dda0f3c231cf1541a3c95162fbea8bc9517f24d817dfa3701ffc7efe0bbaa53230c4699b7d5a94ae019e58827ea1a6a1441deca8b321d97777b13f0ff32607455a746198c326fab5338ce4d99239ea86bbf3282bc9517d26726dfa249c0ffcb81d1559d2a331865de56a7f0bbfce58e78a2ae59cbeb20efa8ebafbac83bea5aa22ef28e3a2fae8bbca3cef1ea22efa8f395bac8bbd2c8bbb20ef38e3a8ed445de516da2dfbffdfe1d77de5fe4b1a4d2c8bbb20ef3fe22f7ef2fb24dfd22db167fdee2dbb5bacadb9fb7709fb7fc25bebc93787dda24c6f5e27d811dfa17efed6c074deeb56c034dee976d054dee79be0a9adcb7de029af43dbc029af41fbd0d9af40162dfa4bcb371123479260dfbc4648c89e3a0c95814d817f30b1d3f0ada021dc73e80f93a7e18b49feb38de7bfe998e1f046d9e8e1f00ed231ddf0fda5c1ddf07da873a5e095a858ee33d9e393abe07b40f741cef2dbcafe3bb409bade36f81f69e8e7f0ada2c1d2f07eda7166da68e6f066d868e6f02ed273afe32683fd6f18da04dd7f10da0fd48c75f026d9a8eaf07ed873afe22685375fc05d0a6e8f83ad0ded5f1e741fb818eaf056db28eaf01edfb3abe1ab4493abe0ab4efe9f84ad026eaf80ad026e8f872d0beabe3cb40fb8e8e2f056d9c8eff0ab46feb781968f93a3e0ab4063a3e0234790f671868f26dd521a0c9fbe58340936fd00f04ad898ef7074d9e95c6316ae47b8e38468dbcb38963d4c877af178126dfdac0b167643c0e1ca346be01f60bd0e43d9605a0c9b75be78376a58eff1c34f9c6fdcf4093efd8cc034d9ec5fe0834f91ee25cd0e41dcc0f4193ef46578026dff298035a731dff0034f9a6d7fba0c97b20b341936fb1be079abc6f3d0b34f966fd4f412bd6f199a0dda2e33340bb55c77f02da6d3afe63d05aeaf874d0e4db1c3f024dbeff300d34f9a6da0f416bade3534193774ba78026efc3bd0b5a5b1dff0168f2dde3c9a0c9bb08df07ad838e4f02ada38e7f0fb4a48e4f04ad44c7278096d2f1ef82d649c7bf035aa98e8f03adb38e7f5bffaafd4fed97afebf97410dff994caef5c70fe9467cca7212e0cc813e7395611f0605eafc55ef654529553daaf7cbd5ea92faf41dea762cf3b99c9fbb45e57815eef2923ef0248f33fafafda3627b4d6402f77c6580eaf8165ddb24c3bd04f1aeb6eaacb7bda51794f194cc28d3e489a7fd74cea58b64737a08e9e7d4ba97d40ea5a001ee29486b830b8f12a95c4f3ed9af09c069ef8f7936489ab3a81fb569c6d88ed1e9059d78a20cd29f0efa403ff705f9775cbbce4e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1487f02f68f4bbad7491845c3beaed3f1f324b1cf55d6affa755e847e1dd7fd7b0df57adb1b652e8034ef37ab4abb51c70be1ffb2dda2b6a5837ec26ab7a5e45708e5390d3c2efa8bf3202f59f76b162f245e1c5bdea972371ea792ea3913d5c76e3ee3f6bac55357fb2bf6dda2a7b8bf9e3378b06fb41078dfd0bf0958cf1b500607fb78b5f542f2c37de935d0247e0e185d6c673c96487bd04ecf63dfb4a439aabd957ef1f8b77d2ae9b2dd3801654a0717d6ef0248730adabed7741c9f0d791d7c7bc7f27f99aaeba716ff54998fc55fe6243e032fdbf79825ef23c01a53dee73d7f9fa783e4237a01c4bfd9ac2aada4133fc46b6157fb883c3b8bece672e78ce58a20cd714bf9d341bce53f66f01c3398d536390bf5ec1d38febb6a938e4778d40e3c9234781ee4ead879c6e0110ec90fdbd146461a59b600d2bc0b6d942a8bb4f352cea86380ebe398acdb761c338f0b094b1955fd98714515efc5fefcd727d05ec4fdfcd7275087f039adc0587f7b58bf70350aa28f2d92e637c671d4c535066e4bd34ff459d2fc1edaa16bf4c3b8b99ceb7f51d76d51e7fac71df02482f3afbdd554ddf11d8f31271cf0382a67d276ec3a6994a908d2b484723a388fa9f63dc26390b78b6d8e5ec839d429c38b0248f3df8cb623ca47bc563d5d27654959cf07db5bca2269fed568a78e3a6072b9dd8e4099d47a5fb39455d2fc3bb47fff17cee7653be171f8b2e617fe5fa6eada03f14f95f950fc654ee2bb9fb27d0f59f23e00ac31e57dde7ba772be2ff9885e00f144f3aab4924efc10af855ded23f26e1bb29bcb9d32962b8234872de54f07f196ff90c173c860cebc87d4bc2a2ef5c865bb7938c2a3f6e091a4c1fbc7726cc7f71b6df7b55c7d7b35eabc19bfbd2a1ab6cfd780a72e9efdb65db398f7506de783ed0d7e3c1f6cae999b06e7bf8f836dce8b6e9ff92fc1f75c03284760943530d81cf95c8a3e9bf700db826efa2cffb35d33b4049febe2feb4709bd702783d22dce67106af47ee046e55ef653be17d44d1ded4bf8ecec94bf17a4b8e31e63939de47eb08ecb8ac70bd61298b782069f3e1fff2bfbf04f6eb93cf5ace8c9f359651febe69a4b3e5d304968ded5d8d9264d2e43f637062db2ce96cbeca7e80754ed665ee2b785f54d2f436da2433addaf6139b56f923db51bcc3f604eba4abfb4851dfea96fc14a3dc03c2ef9bbbb88f92ebfb53786fc545dbeea88d4ee2bd8bf8beffd07d8ced9ecbeb865745c185f7335cb6e951e723a72c79c7e7456aacadbfdfe6455df6f77fd63dcd26463c9ebcbb94dbda399b17272c3c2eeebf54e7c5094bde317a31de764fc4e6c5710b8fabebed282f8e5bf28ecf8baed6fb55362f8e59785c5d77457921f9e5ca7c8280b989118f27efd231785faa3a2f8e5a78e2bf2755bd17472d79c7e7454997eafa3fd18b23161e57fd98515e1cb1e41d9f17ddbadbee5fd8bc386ce1395cc75e1cb6e41d63bd1867bbbf64f3e29085c7c1bdc66abd3864c93bc6f3c32e78afb13a2f0e5a780ed6b117072d79c7e84599ed3ea8cd8b03161e57f741a3bc3860c93b3e2fc6745679efaf8117fb2d3cfbebd88bfd96bce3f3a2ac9bca7b5f0dbcd867e1d957c75eecb3e41de33554a65e54d6c08b4a0b4f651d7b5169c93b3e2fc666ceb5f6d6c08bbd169ebd75ecc55e4bdef17991cc1c53f7d4c08b3d169e3d75ecc51e4bde31d68bccf5e4ee1a78b1dbc2b3bb8ebdd86dc93bc6e348a65eecaa8117bb2c3cbbead88b5d96bce3f3627ce6fed3ce1a78b1d3c2b3b38ebdd869c93bc67b2e997ab1a3065eecb0f0eca8632f7658f28ecf8b4e9963eaf61a78b1ddc2b3bd8ebdd86ec93b3e2fc665fac4b6d5c08b6d169e6d75ecc5364bde319e7766da8bad35f062ab85676b1d7bb1d592778ce79d99fb17afd6c08b572d3cafd6b117af5af28eb1edcc9c776ea981175b2c3c5bead88b2d96bc633cefcc78f14a0dbc78c5c2f34a1d7bf18a25ef18cf3b33c791cd35f062b38567731d7bb1d992778cf522d3766eaa81179b2c3c9bead88b4d96bc63bcaf95693b5fae81172f5b785eae632f5eb6e41de3f548e61edfc61a78b1d1c2b3b18ebdd868c93bc6bea2cc39f8861a78b1c1c2b3a18ebdd80079bb7a5f47f29067b1da185e14409aff6c3c8b15e5a3ac039f2bc3b2bc147b59b2cf95ad8f28cb4b501649f33f8c67f9d63b607254d64c9d7911caa4d67bce525649f3bfe099e17f8367cf659bbc01be5dd2e2c2ffcb54dd3348e29f2af3baf8cb9ca9abcf03671af2c1bcd7026b4c799760def26cbae4237a01c49bb4a84a2be9c40ff15ad8d53ef2828e23bbb9dc0663b92248f382a5fce920def2af3378d619cc99f71ea09e493d72d37665995e88f0a80d782469f099bd371cf19c33788443f2c3e70c1b196964d902487385f6509edb95e720a59c51cf483a68cbaa7d4652f2c3678b5f0346b38caa7ef483673f3b6abd4350a5950837aca7d4d054593b3b2aabe425eb96f9cec028635294d63d63aaa68c9d0c46c5d3d5816738ce864cd51d2fba024f17073c8eca99390e7533cad4d9285311a4c1771bbb3928671ee42beb96f96e90b78b6d8e5ec831f90ec38b0248d311dab3ea7c9475a8fa5b6a294b4fc76591754bbbd4b30ef2ee6ee49d32f24e04e76fe720a87effea0ecc3d1c30abf5f68a7fbd99fdeb2ebd2ea953924f0acad41b3c88ab4c98b79ce7493ea21740fc5e38cf9374e2871cbf845dd565d996c86e2ed7d558ae08d2f4b4943f1dc45bfe5e064f2f83596d93ee706ee7607fc8d4819e0687cca7c0bb5e11def504ef240d1eff4a1d79d7c3e0e961e4ad78e41ca71b6872ae20fc09f87fb20eb8cd76af9b855bb4eec0683bd7e9143f63b5e73a9d8051b41ec0d3dd9167e6b6bec3f0078fcb8d8c34b26c01a41902c7c68425addaeffe19ca256317c638ce4fa64d6fe4c02f1c5731007f02c3c300fc92723674c073695035b6e29c8a19b3cb268ceb3f2edbf52868050626fee6598a910f1ac61b58b420387f08c902d06408c986a0e51bb6e0d095925e86b4736117fa21eb2e30389b004b9c79e3f09b325557751a038f8baaacaace657a5dbaea0c9a3da9621cd68f8606676dea8efa5f836ad245adcbd57630f78934cc9b75b0c051fe0da0bc699897fcd4b629d4f19965e553face9e3077dab8e91573d02873c7c6785e70fe06307fa30c77b5d36105c00263e3d0d028173618f23fd93097c6cf598a63dc9ade04909f4c97826f9738f04dad5fc6aa2d2f9b3ab5dfdc31532795df3f777a79c5a419d3716b36319c8bdad2f2ff46a0d99a784cab266cb670d9c616cd36e1a8c04d409323d725a009cfa5a03580b8a437b78c93eada12d62fbb94fa9f32a7a12e78e3a0aa0ac8e158b5ab6aff55a7729707d953a12b82ece654430daba185d550c26ae8603554b01ad1527dd542dd7556674f6a685f3594af1aba570dd55b1c6487e2bd35a81a6a574def02e7ed41f6544b0d9ddb3ac80e8dab6e57aad7d5d5a7ddd4a734d429bbba15a04e73d5659dba0451a79dea7453ddb250b7afd4699c3a4556a77fea944d5d82a84b0f75a9a82e9dfa68affb86e1ee30dc13867bc3705f18ee0fc3036178300c0f85e1e1303c128647c3f058181e0fc31361e817862783ec50d203c2f054901d6afae9203b0cf5e0203b44f5d0203b7cf5f0203bb4f5c8203becf5e8203b24f698203ba4f9d8203b4ceef8203bd4eec4203b5cefe4203b34f0d4203bbcf0f4203b94f1cc203b1cb21a3a590dbdac866456c337aba19ed550d16a08e9854176686a35ecf4e2302c09c3b361782ec80edbbd2cc80ef3ad86ff5e1964870b57c388abe1c5555782ea42515d0beab6bdeabe52b796559796bae5adba6255d7b4eaaa578f2ea84739d4a32dea511ff5e8937a144c3d1aa71e15548f4eaa4749d5a3b5ea5163f5e87565907d347f7f907d7543bdcaa25eed51af3aa957bf8e06d95703d5eb9dea7549f5faaf7a1dfa7490bd9dad5ead575d9cea16b7ba95ad6eebabdbee6a68f9b7c3f095307c350c5f0bc3d7c3f08d307c330cef84e15b4176f8e1ef04d9218cd510c8df0fb2432babfaa8866cfe51901d0afa27417688e9f782ecd0d51f04d921b13f0ab2436dab21b8d510debf0cc3c74176d86f35fcf9af83ec90f6bf09c36fc3f05761f85d187e1f86bf0ec31fc2f0c730fc4d18fe360c7f1786bf0fc33f84e11fc3f04f61f8535035f4353616bfd333b7e8f9b28a8a71d366561457cc289e36776ac5a499531716cf9f5431b178c6bc71b3c74f9d311f175eaf9b2719b7bbefecd9650b8b274d1f3b6e41f18cb915c533c6178f993177fad8f30ed427f442375c9863d9d8b1d1997d3dff73907eab9699bea7979311d11faabe6c1fd6c6908f6bb3d0ffae658166eaa397dc3e19903dd72d9e3375464571b2787af8373cb8ce983f6e6c8762fcdf9cd0e43915c5732aca6657148f9f3d635a7149075cef078d6b51883f35760353704dedccf9573d9672adaad89166b570e007cd6a47fa71b3cf41fa692d33fdafb529e1bfd466a166cd6b47785bf3485be6cc1d5331bbacbc227ae1d69f67e10ecd6b51ccbb6a59cc3fd726b3ff5e9b859ab6a81d618716b5c86c700e9905ff0f4017f891c0fa04009b2d6c6f00000021291f8b08000000000000ffed9df7771c45b6c77b64490e638de51c018171906549a3916c598e12b08071029b60927192c1605bc61669030b1b6161173692173647364736e765132cbb0b0bcbe665c30fef0f78efbcc379b77aea3e7d55aed6d1882e71dbdc3ee7baabbfaae9fad4b76fd78cab7b7a725179f93745ce96c750cc8f8e5df8efdd765d7c694b5b8afb2a86e4cc6584b32a239c6332c2599d11ce9a8c70d66684736c4638c76584737c4638276484339f11ce8919e1accb086721239c9332c2599f11cec919e19c9211cea919e19c9611cee919e19c9111ce9919e19c9511ced919e19c9311ceb919e19c9711ce1332c2796246384fca08674346384fce08e7292972360127cf859f6ad70bec7aa15d2fb2ebc576dd68d74b6c1fabedb6d9e7528a668a16e76fad8699c24c8a979cbfb55374502ca3586effd660ffd649b182a28b6225c52a8ad5146b28d652acb39ef4509c46713ac51914afa23893e22c8ab329d6539c43b1816223c5268acd145b28cea5388f622bc5368af3292ea0b8d061b988623bc5c51497505c4a7119c5e5143b28aea0d849b18b6237c51e8abd14bd14fb28aea4b88a623fc5d514d7501ca038487188a28fe230c5b51447288e52f4535c4771bde3d90d143752dc44f16a87f33514afa5781dc5cd14afa7b885e2568a3750bc91e24d146fa6780bc55b296ea3b89de26d147750dc49f1768a7750dc457137c53b29de45f16e8af750bc97e27d14f750dc4b711fc5fd96854f8407281ea47888e2fd140f533c42f1018a0f527c88e2c3141fa1f828c5c7283e4ef1098a4f527c8ae2d3148f527c86e2b3149fa3f83cc51728be48f1258a2f537c85e2ab145fa3f83ac56314dfa0f826c5b728be4df11d8aef527c8fe2fb143fa0f821c58f287e4cf1138a9f523c4ef133c7f39f53fc82e29714bfb2da1376fda45dffdaae9fb2ebdfd8f56fedfa7776fdb45d3f63d7bfb7eb67edfa39bbfe835d3f6fd77fb4eb3fd9f59fedfa2f76fd57bbfe9b5dffddaeff61d72fd8f53fedfa5f766dae8fe52797cbe3a281a53b4a69cce9e8ed32f3e36ca67bfdcd5cdb1963ffc6eb06ab57db6d5ee7ac5e63b76b1cbdd66ed73afb1967b7c7397ac16e171cbdde6ed73bfa14bb3dc5d1a7d9ed698e7eb2dd3e19f4bcfd5bb963e595d1c65829071ae75f156835561b035a2def0eb4b156ab018d8f6f2d68e3ad3616b409561b075ade6ae3419b68b509a0d5592d0f5ac16a13419b64b53ad0eaad5600cda6663409b42956ab076daad5268336cd6a53409b6eb5a9a0cdb0da34d0665a6d3a68b3ac3603b4d9569b09da1cabcd026daed5668336cf6a73403bc16a73413bd16af3403bc96a2780d660b513413bd96a2781768ad51a40e3f3f264d04eb5da29563339c5e35cfc1aab5781762a9fcba02de0f318b4857c0e83b688cf5fd01643dbac35f2f90cda12ab713e9bbf2db7e5ee28adb1acb4dbecb733edfdd29ecd7ebbd2df6fd18c8d2ba301afbba19d4ef06a952da7784f401bb69db3c1edb05e0de533a12ed7633f784c627633ceacb0e55543bc6eb9f3ba02d459e1e97f77946effbb1c9e2e87b906ca8172769fe6ecb0978a73f67ca8ebe61ebf3f1e8f39bb1e38d2cfd9f676cdd9612f15e7ec6ea8ebe61e7f563b1e73f622e00890b39d6172b654d49c2dcf8f44913ff7f8ff0dc763cef60247fa39bb4c7376f84bc5397b33d475738fff0f7b3ce6ec51e0483f673b3bf5b3c1b0978a73f64ea8ebe61ecfa71c8f397b2b7004c8d9dd3ace0e7ba93867ef87ba6eeef1dcdef198b3770147fa39db152867db3567a3f2b5ae28f2e71ecf331f8f39fb1070a49fb37b747e76f84bc539fb15a8ebe61e5ff3381e73f653b66cae333c61af33cc03ed49ab9d00daafad7622684f59ed24d07e03d70659fb2d5f3704ed77563b05b4a79d6baa467bc66aa782f67bab2d00ed59ab2d04ed39ab2d02ed0f565b0cdaf3566b04ed8f565b02da9facd604da9fadb614b4bf58ad19b4bf5aad05b4bf59ad15b4bf5bad08da3facd606da0b562b81f64fabb583f62fab7580f66fab2db39ab926c9d7be7e6cb571d0f7ee28bd1c8daf774583979cb3dd0de52561798a8568f07d40dcd6d2f4db6a377d6f8a86dff7a5c0d31ca0ef796863383ccdc0d3923e4ffc3db9d6f4f71b1fe326c7d33cb4d504fd2a06e8570edae27df336b757000dc78da287b12d7dc612deebc4fbe6ed3660640dc7311e87f9fc31ef31ff01de00e752fc3983dbe3efff32c752d0b9ced7eb07d8fecb6a75f0771cd35b1c2d505ec679c16df1be79bb1518b93f2da3cf581a2e63b3c3186a8cc8415bbc6fb76d3cdf978cbe67c33aae05d05e8631a934d231a90ed81a81b131908f49c75a4adb21deaf72d0068f6dec792be85ce7d9aaf2da8c6d1372036c01cebf52a59fdf703c483f8f4b453caf87c353049e10e77ea0f3b588effb2f46e9e65ac9f1aac5f1aa0075dac0bf5200ff86fa1cc2ed29b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb37c66bcff02af6f72bd46218cacb5024f8879fef8bbe4bc2fbb36d7751e80eb3ae95fb72815f19a25dfb7b7d0e97335d479343750f7615bf65d1bc46b9a8d61bd1bd67d1675d1b1d762435e434cba0eecbb7ed9905adba53da1aeb799e75c9867123439be367a3c0d709fca204f738ea7787fdc6287c7e4e9f355036c21aefd557a2d12bde2729ad7f6f01e83b0c7a53c7e702e544583c70f7c9f694fbdedc1d730f97a79bbd37635d4f9466ee0d8f03d90fc5b07ee3d4fa64e87b36f7ecd42d03b9c7dd7dbd732478db3ff26782dd7f9368ca9bb205743dcff81e372047dc5a51bca78dd3cfdf7e1f275fc62053c25e00931ce04fabc51c47320edebf81d8e57becf315ca71dfceb08e09fefb3286f737bcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9f19bf2bcaac79a8d72a847194ee7d88af67f0734778ffe6bace96aa8176435f87e36b4e8b9c3e57439dbbab06ea6eb3e5bae8d8fb1d928e6580eb79431e4b6eaf0efa83d782427d9fbbcde169f378c1e586d4da2e5fc74fdfe381ebf845c7d7568fa7a1ce57bcc68a9ee2f9dae2f0e0b5d1bae8d87b4bf2b09fd1b87728292fb83d3c97da40e3327e3f3ac471c6f712f7be1e6e0faf5f5f63bdad8f421dfb5231e4b8b10cfad41d1d9bdfd550e7308c7d476c19efe1c07b476ef5fc9d97a1ae53b37f819ee3161fdf15c0d90ded60db5dc09a52db6dd876ce06b7c37a35946fa91aa8eb3ea78cbd6676738eb8cf52f3bdaec5795d01ea2cf7f4bf3b4ab7ff9d0e4fa7c36c8ec9759067b7c2fb7fa831697982470bc123ae839f8342bd77baf757baf715e2385aebd4e1d756439ddb618c4aba7fd4f71e10fa7d8cf7ed7b1f73df1786739fe72bfd3eadfb60bc48fb3eadfb2087f03eadc8d9ff22d83f73d546c9ef2d5ce72167ffee67727e0dde07c6751e81f1e229f8ace37efec67ba646e3ff5749f749737bf8b986ff369cbe1be66550bf3b4566cc0964c1cf095ce793ce31eb48e05eea79eda309af65aff83954f8ff17d73fe343eacf90b5e77ca7d317ceebe5d017aef345e73360a8e77ca7dfd7c19f49781c68f3f495eb7c0dceb5c7e0331e1f27fc7fc7e39ebff332d467407ceeedcaf4fb1c1f5f7cbe6b37b4836daf06d694da6ec3b6f93320b7c37a35947f0a633ad7633fd86b6637e7087f8e4276f775edceeb0a50a7cbd3ffee28ddfeaf7478563acce6987c0bf2ec71f80c186aacee4af0681178c475f0bb41fc3e82cf90f5cd75bc5cff9fc6cf52383e3f15745ecdfffee7ceabf93e232c723cc6cf08cfc0389bf7d475e70bf9fd32cdfb86f1bb124dd0eef39e76bb53f6b3197ceb866dfc5cf072b61de0b9a5f17744f0b982cc804b379499a100afabca00e3980c30566780b126038cb519601c9b01c67119601c9f01c6ffffbd6fc18cf90c304ecc00635d06180b19609c9401c6fa0c304ece00e3940c304ecd00e3b40c304ecf00e38c0c30cecc00e3ac0c30cece00e39c0c30cecd00e3bc0c309e9001c61333c0785206181b32c0787206184fc900e37c654c85717158c6d248190d4fa8df27ace437f146e3f709977ada0a705da45469dff15a4988e7a755fa7b89cc50888efdfdaf408ca591321a9e96f4792afe7dcd16f0ccf73b9801185fd26f48497a6e1bde9fbe242c63e9a53c5b2ec4b31647fafc30bcc7604958c697f48cb310f71054fa8c33dfef6e2e09cb581a2963a87b42f0fe93e1f0f8ee13591296b13452c650df83c0ef6a0d87a71d3c2b793c0bc0581a2963a87ba62abda70fefed6ef77826891179d27ebe68bba7ad6502face0c59631c9f01c6091960cc678071620618eb32c058c800e3a40c30d6678071720618a76480716a0618a76580717a06186764807166061867658071760618e76480716e0618e7658051ff5fa88c2f3723f234a4c73368fe03db0af1bdd64afbbedcc393e2f73e07f51ddb0af08c938afb8ecf02c912e3b20c30067e9e8dfaa88ccaa88c7a5eab8fe219d547f5511995511995f195ce9885315c1933918fa591321a9e15813cebac80670578c6af5b1296b1345246c313e2d9b8796863383c5de0d90a8f6701184b2365343c019ee3177bd655010f3eefaecbe35900c6d248190dcfaa409eadac80671578b6d2e35900c6d248190d4f886716e6a18de1f0ac06cf56793c0bc0581a29a3e159933e4fecd9ea0a78d68067ab3d9e05602c8d94d1f0ac4d9f27f66c4d053c6bc1b3351ecf02309646ca6878d6a5cf137bb6b6029e75e0d95a8f6701184b23651c077a8a3cb167eb2ae0e906cfd6793c93cad89101c6651960cc828fcaa88c9218f5bc561f2531aa8feaa3322aa332669771790618f5582ba354c69ef4194b9532f6004f77fa3c6d81fa19fffed469765f293e13a164bc3addf16a9de35501ea9c06fe9d1ec0bf1cb4cbfbe66d6eaf52e6530530076abbc4bf8bbcce696f99e38759ceb0eb1ad0f137dc5f65cbfcdb735c1f7f878ceb6cb63ff4c1bf69c94b15f4f78cf4fbdb36d4b9cded214f8b309ea5c2787a84f1cc15c6335d18cf1a613c9384f1ac14c6335e18cf42613cf8bb5b12783a85f1cc13c6b34818cf0c613cf5c2782608e32909e3a916c6d32a8ca74918cf7c613c3385f1ac15c6335918cf62613c79613c2b84f1d408e359258c6781309e59c278a608e399288ca756184f51184fa3309e66613cb385f14c15c6b35a184f9d309e2e613c6385f1b40be399238c679a309e82309e71c278da84f1e404f0e4a363ef59c8c3df7b40ab725e6bc6abffad1ff8fb9956af82d79c65cb633cfb3e1334beb67b96e7b5e8d399d0976e5b2ebeb425f609dbea866d6eaf0e38ce12c2d3268c679c309e82309e69c278e608e36917c63356184f97309e3a613cab85f14c15c6335b184fb3309e46613c45613cb5c278260ae399228c6796309e05c2785609e3a911c6b342184f5e18cf62613c9385f1ac15c6335318cf7c613c4dc2785a85f1540be32909e399208ca75e18cf0c613c8b84f1cc13c6d3298c678c309e85c278c60be359298c6792309e35c278a60be3992b8ca74718cf52613c2dc278aa3c3c3d8178f8fa2def9bb77b84b41de038c4df8b3f3b509fd6db7dd5d8fd323fb7570d75eead2dafcde75d7c2d73b9d7dbf15c5e0f1ead0fd4173e1e39e7f8046ebb03ef2b88802172fc893c3c21eec708d4cf417998e2f3198ac6ab731cafdc6357803a67837fe704f0cf97dbbccded29b3322731e3ef32306b1eeab50b6164ed8ca03c1dc54a7f3be21ce009f15e11c8f7781cdbe0f4a9dde33bd7c15cdd10a09fbe7387b73778da6e88d2f562e330bcd8e8e1d938ca5e707b95329f9d4166f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466093e1b1efe8e34b3e6a15ea71046d6d687e589bf6fd4190d5e72ce7637943702cf3901fc09d4cff81ef24d4e9f3a3dbe731d3cbf3605e8a7efdce1ed4d701c2a61de904166f57964cc86879f75c5ac79a8b74208236be784e589c7b115d1e065a8716c13f08418e703f5331ec7363b7d5ae1f19debe0f9b539403f7de70e6f6f86e3a0cccaec63363cfc8c6066cd43bd2e218cac6d0cca538abfdfd8150d5e861ac736034f88713e90eff138b6c5e95397c777ae83b9ba25403f7de70e6f6f81e35009f3860c32abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3fafccaf1d9f0f0b3ce99350ff5560a61646d53509ef6f8bac3ca68f032d475872dc0b339759ef2758700bec7d71dce75fab4d2e33bd7c1f3ebdc00fdf49d3bbc7d2e1c87e39d7943069935374687597343999398353794398959734399939835379439895973439993983537943989597343999398353794398959734399939835379439895973439993983537943989597343999398353794398959426e189e55b6ccac79a8b74a08236b9bc3f2c4cf3d58150d5e86ba6fe75ce0d912c09f40fd8cefdb39cfe9d32a8fef5c07cfaff302f4d377eef0f679701c9459997dcc8667b52d336b1eeaad16c2c8da96b03cf138b63a1abc0c358e9d073c21c6f940fd8cc7b1ad4e9f567b7ce73a98ab5b03f4d377eef0f656380ecaaccc3e66c3b3c69699350ff5d6086164eddcb03cf138b6261abc0c358e6d059e10e37ca07ec6e3d836a74f6b3cbe731dccd56d01fae93b77787b1b1c076556661fb3e1596bcbcc9a877a6b8530b2869f7f98edc5f478961580a50ada0a3586474edf79c17ce1a54518cf52613c7385f14c17c6334918cf78613c0b85f18c11c6334f18cf22613c3384f1d40be399208ca7248ca75a184fab309e26613cf385f1cc14c6335918cf62613c79613c35c2781608e399258c678a309e89c2786a85f11485f1340ae36916c6d3238c67b6309ea9c278ea84f18c15c6334718cf34613c05613ce384f1b409e3c909e0c947c75ee7c4eb276340e3eb196b413bdf967b40abf2b4c1fbd9061acf17f03ecc783376f2b1ed5579dadbe6e11a0d3fb1ad6ed8e6f6ea80639b109e36613ce384f11484f14c13c6334718cf58613c75c278a60ae3992d8ca747184fb3309e46613c45613cb5c278260ae399228c6796309e05c2786a84f1e485f12c16c6335918cf4c613cf385f13409e36915c6532d8ca7248c6782309e7a613c3384f12c12c6334f18cf18613c0b85f18c17c6334918cf74613c7385f12c15c6d3228ca7cac37341fa3cf177ca7aa2c1cb50d7642e08ec4fa07e16cd7e2fb4fb4af1bb2cf177d52e72bcea71bc2a409d0bc1bf8b02f897837679dfbccded29b33227311b1e9eebc5eba55caf5908236b5bc3f2c4e363733478196a7cbc0878028c636d81fa198f63db9d3e357b7ce73a98abdb03f4d377eef0f6764fdb0d51ba5e5c3c0c2f2ef6f05c3cca5e707b95325f984166093e1b1efeeccaac79a8b75408236b1784e589c7c7a5d1e065a8f1f162e009f1fe11a89ff1987089d3a7a51edfb90e9e5f9704e8a7efdce1ed4be03854c2bc3d83cceaf3c8980d0fcff9336b1eeae1f7c05e4e46d62e0aca538a7fa3b2291abc0c358e5d023c21c6f940bec7e3d8a54e9f9a3cbe731d3cbf2e0dd04fdfb9c3db97c2715066655666655666655666655666655666655666655666655666655666655666d9cc8687bfbbc7ac79a8d7288491b58b83f294af3b34468397a1ae3b5c0a3c21aecb04f23dbeee7099d3a7468fef5c0773f5b200fdf49d3bbc7d191c076556666556666556666556666556666556666556666556666556666556666596cd6c785a6c9959f350af4508236b9784e589bfb7d5120d5e86baee7019f084b82e13a89ff17587cb9d3eb5787ce73a98ab9707e8a7efdce1edcbe13828b332fb980d0f3f1b8d59f350af5508236b9706e5295f3f6d8d062f438d6397034f88713e90eff138b6c3e953abc777ae83b9ba23403f7de70e6fef80e35009f3f60c32abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3fafccaf1d9f0f06f9c316b1eea158530b27659509ef6f8ba43311abc0c75dd6107f084b82e13c8f7f8bac3154e9f8a1edfb90e9e5f5704e8a7efdce1ed2be0381cefccdb33c8acb9313acc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc1272c3f0b4717b769d877a6d421859bb3c2c4ffcdc83b668f032d47d3b5700cf8e00fe04ea677cdfce4ea74f6d1edfb90e9e5f3b03f4d377eef0f64e380e3b9559993dcc86a764cbcc9a877a25218caced08cb138f63a568f032d438b61378428cf381fa198f63bb9c3e953cbe731dccd55d01fae93b77789bdb5366654e62366def4ebfed783cc0b6d99fc8e1e16577602f02f5331e0ff6447e8fb9bd02d4c163be27403f73d02eef9bb7f7c071a884797b0699d5e791319bb6f7a6df763c1e60dbec4fe4f0f0b237b01781fa198f07bd91df636eaf0075304f7b03f43307edf2be79bb178e4325ccdb33c8ac3e8f8cd9b4bd2ff5b6cbcf49c3b6d99fc8e1e1655f602fc2f4b33c1e5c19f93de6f60a5007f3f4ca00fdcc41bbbc6fdebe128e83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66366d5f957adbe5f97b6c9bfd891c1e5eae0aec45987e96e7eff7477e8fb9bd02d4c163be3f403f73d02eef9bb7f7c3715066655666655666655666655666655666655666655666655666655666655666d9cca6edabd36f3bfe3e0eb6cdfe440e0f2f5707f622503fe3f9fb6b22bfc7dc5e01eae031bf26403f73d02eef9bb7af81e3a0cccaec63366d1f48bdedf2f53c6c9bfd891c1e5e0e04f6224c3fcbe3c1c1c8ef31b757803a78cc0f06e8670edae57df3f641380e95306fcf20b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfaf1c9f4ddb87526fbb3d9ebfc7b6d99fc8e1e1e550602fc2f4b33c7fdf17f93de6f60a5007f3b42f403f73d02eef9bb7fbe0381cefccdb33c8acb9313acc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc9a1bca9cc4acb9a1cc49cc1272c3b47d38fdb6e3efb363dbec4fe4f0f07238b01781fa19dfff726de4f798db2b401dccd36b03f43307edf2be79fb5a380ecaaccc3e663c4fc6a5d7767c3f1cb75165d7463b62cb63403b6acbd5a0f5db720d68d7d9722d68d7dbf258d06e80feb076a32d2f06ed265b2e81f66a5bbe02b4d7d8f24ed05e6bcbbb407b9d2def06ed665bde03daeb6d792f68b7d8722f68b7daf23ed0de60cb5782f6465bbe0ab437d9f27ed0de6ccb5783f6165bbe06b4b7daf201d06eb3e583a0dd6ecb87407b9b2df78176872dcf07ed4e8ff6765bbe10b47778b4bb6c793c6877dbf204d0de09655ebfcb962782f66e5bae03ed3db65c00edbdb63c09b4f7d9723d68f7d8f264d0eeb5e529a0dd67cb5341bbdf96a781f6802d4f07ed415b9e01da43b63c13b4f7dbf22cd01eb6e5d9a03d62cb7340fb802dcf05ed83b63c0fb40fd9321ea30fdbf261d0781cb816341e078e80c6e3c051d0781ce8078dc781eb40e371e07ad0781cb80134ce9d1b41e3dcb90934ce9d5783c6b9f31ad038775e0b1ae7ceeb40e3dcb91934ce9dd783c6b9730b689c3bb782c6b9f306d03877de081ae7ce9b40e3dc7933689c3b6f018d73e7ada071eedc061ae7ceeda071eebc0d34ce9d3b403bc196ef04ed445b7e3b6827d9f23b406bb0e5bb403bd996ef06ed145bc67181c79f778176aa2dbf1bb405b6fc1ed016daf27b415b64cbef038ddf73ee01add196ef056d892ddf075a932ddf0fda525b7e00b4665b7e10b4165b7e08b4565b7e3f68455b7e18b4365b7e04347e9ffc0068edb6fc41d03a6cf943a02db3651e17ccf967ce19ee33fb5107fd6bf270b3360eb8bba3743f33715bbc6fde2e0223fbdd3afa8ca5e132b6388c86a714c033cc215e86fabf1f33189e36f87b5a3c81fa19ffdfafdde953d1e95301ea9c0afd6c0fd0cf1cb4cbfbe6ed76683bc431472f6aec7e17385e54439d27ed9b9c590de523efc3e46faba72fcb03f785f7cde3d2f25168bbc369bbd9691bc75e5e863abf3a8079590066b3dfcef4f71b9f5f2becbe38a7b89d66e853177890569fb0ed9c0d6e87f56a28bf503f5097ebb11ffcfec5ec2697f95822bbfbba92f3ba02d459eee97f77946eff3b1d9e4e87d91c93e7ea0738029c0f710e2c773878bb19bceb4cf06e3978c775f0fdaf259077cb1c1ede6e011efe8cd30e1a7f56c03908fe7bd32870bbe35ebb879bb50e606cf13036a7cf187fd669711879bb1918595b063c1d813c738ff502c71f7c5fae75eaf06baba1ceffc07b63de53d79c77ff817ef1ff995f8cd21dd36b03f885ff9f8fc09fc8f13002bfb89f350178264403ffa73fdadf7764d795bd5b7b77edcd015ab58389eb9ca71b55a061798c478ba2c1531738e5c9531738e559e5d88253265cdffc57ca748ba7077a0feeefbfe050efa13d476e3adcdfbb7763df95485de3d02369520f9014355f8f86a21f1f1d7bf0533d33196e3eec3f6741c6d84ed4582063dfb868c03e9ed931efd66644313335e68c343331c65a33d3626656cc4c8a99393133256666c4cc8498990f33d3616636cc4c8699b93033150d517926e214e0f931309aff2198b3ddcc24989903335360de25cca74f33b29a4f12669433a39b7917339f92cdff98ccc861466533e29851c2bceb99773bf3e9c4bc5bafa45845b19a620dc55a8a75d6eb1e8ad3284ea73883e2551467529c457136c57a8a732836506ca4d844b199620bc5b914e7516ca5d846713ec5055179e6efa2a87c85f3628a4b282ea5b88ce2728a1d5179467d67549e313733e46646dccc809b196f33c36d66b4cd0cb699b13633d4d744e5196833e36c6698cd8cb2994d34b38766b6d0cc0e9ad94033fb6766fbccec9e99cd33b37766b6ceccce99d93833fb6666dbccecda2d5179f6cccc9699d931331b6666bfcc6c9799dd32b35966f6cacc56dd119567a3ccec93996d32b34b6636c9cc1e99d922333b646683ccec8f99ed31b33b6636c7ccde98d91a333b636663ccec8b996d31b32b8f44e5d913335b626647cc6cc847283e4af1318a8f537c82e293149fa2f834c5a3149fa1f82cc5e7283e4ff1058a2f527c89e2cb145fa1f82ac5d728be4ef118c53728be49f12d8a6f537c87e2bb14dfa3f83ec50f287e48f1a3a89c933fa1f829c5e3143fa3f839c52f287e49f12b8a27289ea4f835c55314bfa1f82dc5ef289ea67886e2f714cf523c47f1078ae729fe48f1278a3f53fc85e2af147fa3f83bc53f285ea0f827c5bf28fe1d0dcca4e240f198dde059bd5dfdfdbd070ff737f4f7351cbcee40fffec3076e6ab8617fff550d7dd7f71ed977a0ef067cf1d57618e229cb9e234776ddd4b0ffd0dede1b1bfaaeeb6fe8dbd7b0bbefba437b8fe28b6eb32f9a776c8bbbf6ee4d6eecdeaa9740fae0081bfd847d1d4f06af1fba6f9f1e89215f18c98b9e1e618736d97791d5767b5bf99dbae1e881befe8662c321fa77d7017a4defde9606fcdb5132f9687fc3d1fe5d47fa1bf61de93bd8d0d682fbbda776049d78a27e042ffaeffae1f73cfa3fac10a5ab91130300", + "packedBytecode": "0x000000028df71de50000003d361f8b08000000000000ffed9d09941545bee6b38a62d16b95b82bb8948a82acb72ec58e50b8e0ae08222020140508c84eb183b28328822cb243b1ef8be0d26def76b7bda96d2f6adbfdba5f77bff7fabd7ef3ce9cf3e6cc3b33f366c69e8c7be33ff511449675cb8cf2bb12794ed48dfc2a32e3175f46462e9199911764a6bf86214fc71b84a14570fe24ff2fd3bfc92f3695c4b8aea44bcebc1ce1cccf11ce0639c25990239c0d7384b3518e7036ce11ce2639c279518e705e9c239c891ce1bc2447380b7384b32847382fcd11cea639c279598e705e9e239c57e408e79539c279558e705e9d239cd7e408e7b539c2795d8e7036cb11cee639c2797d8e70de90239c37e608e74d39c2599c239c37e708e72d39c2796b8c9c6d8053eed9dfa67f6fd7bf2df56f2bfd7b87fe6dad7fdbe83216e8f9b661681786f661e860fc4f19a36edca7c2d0d1f85f69183a85a17318bae8ff15ebff750d43b730740f438f30f40cc39d61e81586deda8f3e61b82b0c7787e19e30dc1b86be61b82f0cf787e181303c188687c2f070181e09c3a361782c0cfdc2f07818fa876140189e08c3c0303c19864106cbe0300c09c35361181a866161181e86a7c330220c23c3501e865161a808c3e8308c09c3d8303c13867161181f86096178360c13c330290c93c330250c53c3302d0cd3c330230c95619819865961986d7836270c73c3302f0cf30dce0561581886e7c2f07c1816856171189684616918968561791856846165185685e18530ac0ec38b6178290c6bc2f07218d686615d185e09c3fa306c08c3c6306c0ac3ab61d81c862d61d81a866d61d8ae596447d811869d61d81586dd61a80ac39e30ec0dc3be30ec0fc381301c0cc3a1301c0ec391301c0dc3b1301c0fc389309c0cc3a9309c0ec36b61381386b361783d0c6f84e1cd30bc1586af85e1eb61783b0cdf08c337c3f0ad307c3b0cdf09c377c3f0bd30bc1386ef87e10761f86118de0dc38fc2f0e330fc240c3f0dc3cf0ccfdf0bc3fb61f8200c3fd7da87faf717faf797faf757faf7d7faf723fdfbb1fefd44fffe46ff7eaa7f7fab7f7fa77fff4efffe5efffe41fffebdfefda3fefd93fefdb3fefd07fdfb8ffaf79ff4ef5ff4ef3febdf7fd1bfaa1f6f75f34cbc49503d950531b539a563cad57d7c31d3ec27547d500df4ffe4b758eb057a5e7ef3b4de50cf3734f4467abe91b19e267abe89a117e9f922436faae79b1afae57afe7243bf52cf5f69e837ebf99b414fe8ff650a96f9515a032de58126f52f1fb4865a6b005a23591d688db5d61034d9be8d40bb486b8d41bb586b4d404b68ed22d02ed1dac5a0156a2d015a91d62e01ed52ad1582d6546b45a05da6b54b41bb5c6b4d41bb426b978176a5d62e07ed2aad5d01dad55abb12b46bb4761568d76aed6ad0aed3da35a035d3dab5a0e95d2cb80eb4ebb5d60cb41bb4d61cb41bb5763d683769ed06d08ab5762368376bed26d06ed15a3168b76aed66d05a68ed16d0e45ce156ada97a266d5f7a19ade783769becdfa0dd2efb36682d65bf06ad95ecd3a0dd01798bd65af671d0da684deab8fa5f671d2f0be26adf52156abd5de25e6fb866b5de6ef1af37a9dacbee41b5d765904f17f0aa878ec7f83c4309e69da783e4237a01c4ef83b4924efc90764ad855dbd355c77bd4b05c6763b92248d3d552feb220def2773378ba19cc6a9bf4048ef8eb6cc7a4afb3b59eb2aeb30321ad59f7e498f955acb30f0287833a5beaeb6cada7aceb6c05a435eb9e9cbf7d15ebec60e0705067bbbaa9b3a9a4afb3997b264160af7b722df155acb3638123fe3adbc9d7d9da4f59d7d9e721ad59f7e4baf6ab58672b8123fe3adba5ab3f37a8f594759d5d0369cdba27f758be8a7576097038a8b315be9dadf594759ddd0e69cdba27f7fbbe8a75761d70c45f67bb39aab31d7d9d0d32fd5f4160af7b72eff9ab5867770147fc75b6c2df9fadfd94759d7d0bd29a754ffa41be8a75f6b88eab7e860f753fc3f5a0fd426b3780f64baddd08daafb4761368bf86fe42d13e92be44d03ed6da2da07da2b55b41fb8dd1f7aab44fb5761b68bfd5daeda0fd4e6b2d41fb3badb502edf75abb03b43f68ad35687fafb536a0fd516b6d41fb93d6da81f667adb507ed1fb4d601b47fd45a12b47fd25a09687fd15a0ab47fd65a47d0fe456ba5a0fd556b9db4a6fa29a5efeb5dad3501aeb220be3a9a000f64ca33e6cb20dec12d4fb2087830af92f8f3eaa8ca7ecec3569f53f612e04939287b02f2a80d4f0a783ac6cf937ec7af34fef5a6b771d2f034017925a15c9d1c942b0ff29275cbbce457041aeed39d2c8cb19f6784175e799097ac5be63b03a368d8c6489b2bfb8f3ac6fc2bf03ad897d2e719929fbcbb2c1c25a04b9ae2e6d56cff556b85f07f6c6f3b1a9aa37a99ae179297ac5be64b8151cad3b1fe1953b5654c198caeda883cc84bd6edf3aede0e126f0f3c5d1df1986d9ae4ddb51ef2ee6ce45d62e48d6da74c351ddb3a03b383ebad922fe37a0bcf1f18aeb72ecbab4e6b5e37493b9cedf556276339c6ebad4679d51c0ef687741de86a70c87c0978d72dc2bbaee09da4b90dbc7370ee99f6ae8bc123f329e09176ac1478dad7334f7b82bcf11c56b61b5e4be17980abedd5de609479dbf6ea0c8c290ba38373c2544dc7c81260140def47251d7916b55d932479bbb8aec47729e4dcdcbcb6298034ff273ff3abdaca76794ed95278ee2c536daf79e3df4ea924ee1fb5e171bc0f9538aa8f49bc7ff359106f5d33db25b3bd89bac7e3aa2d4f1a3c322ff97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563cd29f80cf6d49ba8e248ce6f36faeeef3a7bf8522ebd2bfaa5fe7dbd0af137fbf452a897d7ff21c444ba3cc0590e6c3bceab4efe8b87ae640faa9f0592bf3f92b977d76f83c6619cc4b7ef8ac156e4b86e79d8a63cb3bf35d1a17fd6d9706996fea98cf7e76b478eae2f967f434cff0149f03bfc3e051f5f46ff9d56c2efafeb2ed8b44af241e67df5e5160afebf16f97d4397dd6f9c1b9ed071e675c3dbf236db5f4977735f22e80347f80e7a8e4d92a196728692c87cffdc8ba659996a07733d6dd542f2b1c0d8df597c2b292e64fd0a62e83baeaa0ad4c65fbec3af69bc77f1ccef4e327b3e0690f3c2eda1947e71b49dc07e2eec7379f4fb39dc7481a7cb6cfc17395353eef24f97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563c665f2bbe5f5b42c2289ae3671fd2fd19adf4ba64fdaa5f677a7e75beaefbe1a4cfa99551667c77f46c7e75da593a5e189cffbc43d4b674f57d8aa86d29f9e1b767da038f8b7edd3cc84bd6ddc1e285c48b63cb3bd38f1fbfc7d5fdf849c3d7128ba7aef657ec63454f717f4d193cd8371af56d9f0e86e6681fafb15e487eb82f75004de2f87eb48bed8cc712f3b91ec90ffbaf5fd6de360d5c6dfb54d265bb81df4d290bceafdff83d950dd0f66dd2717c86039f1dd96ff9bf4c35f5538b7faacc3de32f737afbde099c65900fe6dd0b5863cabb04f3ced341f211bd00e2fbf2abd34a3af143bc1676b58fc8376090dd5c2e652c5704697a58ca5f16c45bfe9e064f4f83596d932d50cff6c3f1df559bd423c2a396e091a4c1f32057cfe4996da4f97c233eb7d7c84883e72c92e638b451aa2cb6e7476dcf1cba3a8e453d73683b376e0f8c6619cde73c2ff4e7b4be09ed45dccf697d13ea103ea71518eb6f05eb17ae4641f4b145d27cd758bf794e2ecbe0736092e6fbd05efc471dcec9bfaceb2bdb39392e175576c58cdf412b8b9119eb04b2e07982a479dfd866dd22b83b5b96fd306259f1cafc56586170be7f6ebeb396d9e77b1a65917add03ca22693e36ce01e33f6fc99c03bafaa61c9e7ba8f576b09455d2fc0ef6b5dfc3399e6c27dc6fffcdf27f996a3a07c4f11c7bc75fe624ee33b27d7b5bf2ee03ac31e55d82eb9273c03e86070510ff2fd0a64b3a492b5e0bbbda47e43c0ad9cde5ba1acb15419a5e96f29705f196bfb7c1d3db6056dbe48f50cffe0dce015db5d5bd223c6a051e491abca768fb0ea8ed18e3ead9fea8634c076034db4d3c4eba6433df1332efabd9ce11248d2c8be708ff09ed6cc292d6bc5f28c7cb389f1bc677254a21dfbf59f22d8bd9cf2ee05b19cce379c19799b783ef84a7df11c1ef0a0a034e6510c76f87cb72f9c0e8e27beb89e0dcef037f1e237e835d966b008c2eb661b6df272e054659ae00185dbcff85dfc8af0d634760c47d51185d7c97b4aedf73c4ebee46c0c8f45e15de3f6e0c8c2eee73d4f57d1a3ce636815f57638724b360c463ae2c771130bab87f85f7ef6bc388e72eb2dcc5c0e8e23e73b663b0e0f7a1f1fe8f30ba3807ccf61a05ef55c97297006377478cddb260ec0e8c78cf41185d5c4f2620dfda30f60046e41546077d0069c61e5930e2bd7259ee5260bcd31163cf2c18ef044659ae2930bab89f9f807c6bc3d80b1865b9cb80d1c1b57e9ab157168c784d2ccb5d0e8c658e187b67c158068cb2dc15c0e8e2ba3d61307c1e631f6014fd4a60bccb11639f2c18ef024659ee2a60bcdb11e35d5930de0d8cb2dcd5c0788f23c6bbb360bc071865b96b80f15e478cf764c1782f30ca72d702635f478cf766c1d8171865b9eb80f13e478c7db360bc0f1865b966c078bf23c6fbb260bc1f1865b9e6c0f88023c6fbb3607c001865b9eb81f141478c0f64c1f82030ca723700e3438e181fcc82f1216094e56e04c6871d313e9405e3c3c028cbdd048c8f38627c380bc6478051962b06c6471d313e9205e3a3c028cbdd0c8c8f39627c340bc6c7805196bb0518fb39627c2c0bc67ec028cbdd0a8c8f3b62ec9705e3e3c0d8cfc2d8df11e3e35930f6074659ee0e601c103f63fa3b34fdb3601c003c4fc4cf93f66c40163c4fb8e5497fc3698025af27e3cf2bbd2d0606b52ffb93c033287e9ef4b678320b1e612882e5d0b3c1f133a63d1b9405e360e019123f4fdab3c159f00c01cf065b3c7b2a7ec6b46743b2607c0a7886c6cf93f6eca92c788682674f593c1b163f63dab3a159300e039ee1f1f3a43d1b9605cf70f06c98c5b3a7e3674c7b363c0bc6a7816744fc3c69cf9ece82670478f6b4c5b391f133a63d1b9105e348e0298f9f27edd9c82c78cac1b39116cf46c5cf98f6ac3c0bc651c053113f4fdab35159f0548067a32c9e8d8e9f31ed5945168ca381674cfc3c69cf4667c133063c1b6df16cac23c63159308eb5f0c4fd7dd13196bcc6392afb3341edcb2e0c45b01c328e77c4382e0bc6f1c028cb61fffa04478ce3b3609c008cb21cf6af3feb887142168ccf02a32c87fdeb131d313e9b05e3446094e5b07f7d9223c68959304e0246590efbd7273b629c9405e36460445e619ce2887172168c53804b96c3fef5a98e18a764c13815186539ec5f9fe688716a168cd3805196c3fef5e98e18a765c1381d186539ec5f9fe188717a168c33805196c3fef54a478c33b260ac0446590efbd7673a62accc82712630ca72d8bf3ecb11e3cc2c186701a32c87fdebb31d31ceca82713630ca72d8bf3ec711e3ec2c18e700a32c87fdeb731d31cec982712e30ca72d8bf3ecf11e3dc2c18e701a32c87fdebf31d31cecb82713e30ca72d8bfbec011e3fc2c181700a32c87fdeb0b1d312ec882712130ca7278cdf59c23c68559303e078c0b3de305c1883cc5f1f124b1ec98d7f304657fdec29317b8293be6b588a0ec8bf46fae313e97038c637380d1fbe8193de3578fd1efd7de472646efa3f7d1337a46cfe8192f74c65c68c33d634ed4c7545d1915cfe2f879d29e2dca8267317826cb3d91038ccfe700e3736e19537565543c4be2e7497bb6380b9e25e0992cf7845bc6545d1915cfd2f879d29e2dc982672978b6c4e29903c6545d1915cfb2f879d29e2dcd82671978b6d4e29903c6545d1915cff2f879d29e2dcb82673978b6cce29903c6545d1915cf8af879d29e2dcf82670578b6dce29903c6545d1915cfcaf879d29eadc882672578b6c2e29903c6545d1915cfaaf879d29eadcc82671578b6d2e29903c6545d1915cf0bf1f3a43d5b9505cf0be0d92a8b67ac8c637380f1b91c60cc051f3da3676462f4fbb5f79189d1fbe87df48c9ed133e62ee3f339c0e8b7b56764655c1d3f632a5bc6d58e3d7354cef4385e2fea75c5f86d8994f2ea25c3ab5586574590e645f0ef2507fee541beb26e9997fcb2656e41c0ec28ef948c2fbdcac8ef39c30f35add1bf0d411f0b9ebeace332869fa47f1e744933570f98226383caf42c94774dfce52da969df96fc90673419cf22329ea7c9789692f10c26e35941c6f33819cf43643cf792f1f426e36943c633878ca72519cf74329e14194f03329eb6643cddc8784690f18c21e31942c633918ca73f19cfc3643cadc878fa92f19491f17427e3994bc65342c633838ca70b19cf24329e67c8781693f18c24e35948c6f31419cf32329e01643c2bc9781e21e3b98f8ca70719cf3c329e24194f25194f67329e3e643ce3c8782693f19493f10c25e31948c6f328194f0b329efbc978ee22e3e949c6339f8ca70319cf4c329e4e643c53c878c693f12c21e31945c6b39c8c671819cfed643c4f92f13c46c6731b19cf03643c7793f1dc49c6b3808ca71d19cf2c329e52329ef6643c13c878a692f15490f10c27e31944c6d38f8ce741329ed5643cf790f1f422e3e94ac6339b8ca73519cf34329e8e643c79043c89e0fc775213f0ffd5a0e51bcb360e4345f3eaffafd57a3e2cb34ec71b58d6bd16b497757c9d6559f4692d94a54cc7935f6c4afb847995c1bce457081ceb48783a92f14c23e3694dc6339b8ca72b194f2f329e7bc8785693f13c48c6d38f8c671019cf70329e0a329ea9643c13c878da93f19492f1cc22e36947c6b3808ce74e329ebbc9781e20e3b98d8ce731329e27c9786e27e31946c6b39c8c671419cf12329ef1643c53c8783a91f1cc24e3e940c6339f8ca72719cf5d643cf793f1b420e379948c672019cf50329e72329ec9643ce3c878fa90f17426e3a924e34992f1cc23e3e941c6731f19cf23643c2bc9780690f12c23e3798a8c672119cf48329ec5643ccf90f14c22e3e942c633838ca7848c672e194f77329e32329ebe643cadc8781e26e3e94fc633918c670819cf18329e11643cddc878da92f13420e34991f14c27e36949c633878ca70d194f6f329e7bc9781e22e3799c8c670519cf60329ea5643c4f93f12c22e3194dc6f3ac85c7c1f88e691e793f4fd62df3ab49f276b01dd2e35abee2a84cebf5ba1aeaf50abfe45700693e699cf96d1a64ea83e8c2b546c7b16e8837ebc1a3f58eca22db23cfd83e8ef34ee17ba3013004863f8185c7c5fbb68eca794e3d8c7b7cd50d8657e6b62b8234af807f1b1cf867abdb322ff965cbdc828019eb4571106fbdd8187f99feffb8ade2eb46c35f2cd7ab3a1e63bd4caa756cd2eb6a08f9bd0af96ed1f1bc18f355ebdaacd725e3cc0ac716d025cd7f83761999d524ed2f7e636dab8e97c5c79c1e071bc7d1154f702a83f856e0d9ec80c75139d3db669b51a6d546998a20cd2628e73607e5cc837c65dd32bf0d7864c2b1875dd483da6cf3a8b18719781691f13c4dc6b3948c673019cf0a329ec7c9781e22e3b9978ca737194f1b329e39643c2dc978a693f1a4c8781a90f1b425e3e946c633828c670c19cf10329e89643cfdc9783691f13c4cc6d38a8ca72f194f19194f77329eb9643c25643c33c878ba90f14c22e379868c673119cf48329e85643c4f91f12c23e31940c6b3928ce711329efbc8787a90f1cc23e34992f15492f17426e3e943c6338e8c6732194f3919cf50329e81643c8f92f1b420e3b99f8ce72e329e9e643cf3c9783a90f1cc24e3e944c633858c673c19cf12329e51643ccbc9788691f1dc4ec6f32419cf63643c1bc8781e20e3b99b8ce74e329e05643cedc8786691f19492f1b427e39940c633958ca7828c673819cf20329e7e643c0f92f1dc43c6d38b8ca72b19cf6c329ed6643cd3c8783a92f1e411f0448d3d2cffdf009abc5387e3116fd7f1cda0e55bf29067cfb78156a0e3b20ef52ae7e4e6e7af1b7d72f51e21e65506f3921f8e3dbc9d84a72319cf34329ed6643cb3c978ba92f1f422e3b9878ce741329e7e643c83c8788693f15490f14c25e39940c6d39e8ca7948c6716194f3b329e05643c7792f1dc4dc6f30019cf06329ec7c8789e24e3b99d8c671819cf72329e51643c4bc878c693f14c21e3e944c633938ca70319cf7c329e9e643c7791f1dc4fc6d3828ce751329e81643c43c978cac9782693f18c23e3e943c6d3998ca7928c2749c6338f8ca70719cf7d643c8f90f1ac24e31940c6b38c8ce729329e85643c23c9781693f13c43c633898ca70b19cf0c329e12329eb9643cddc978cac878fa92f1b422e379988c6713194f7f329e89643c43c878c690f18c20e3e946c6d3968ca701194f8a8c673a194f4b329e39643c6dc8787a93f1dc4bc6f31019cfe3643c2bc8780693f12c25e3799a8c671119cf68329e67eb87a754bd8b87e37d0a174e6510df063c9b1cf8e3a89c497c0f33ceb13495573b0caf36185e15419aade0df0e07fee541beb26e9997fc3cb3678e62563cd2b7637b3f782109a3689b9cf29426135066996a6a1f77008f8be38723dfd3edd84ea34c0b2dbe4b1aacab3b1d94d3b6efc8fc4e4bdec541bc5eecaa8517bb2c3cbbead90bc92f5be6ad39c8ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccdee7fa61f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf7563563c8b745c5813906e1109a368dbdcf2a4df375a149c3be519f36510df053c3b1cf8e3a89ce967c8771b655a149cefbba4c1fd6bb78372daf61d99df0ddb211be69d39c8ec7dae1bb3e259ace38bf46f02d22d2661146d875b9e743bb6383877aaa91ddb0d3c2eda7947e54cb763554699165b7c9734b87f553928a76ddf91f92ad80e559ed9335b9815cf121d17d604a45b42c228da2ea73ca9f4fb8d4b8273a79adab12ae071d1ce3bf23ddd8eed31cab4c4e2bba4c1babac741396dfb8ecc4b7ed932efcc4166efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fb7ce1f8ac78e49bc0c29a80744b491845dbed94a763badf616970ee9467cc97417c0ff054c5ce93e97770e07bbadf61af51a6a516df250dee5f7b1d94d3b6efc8fc5ed80e5f75e69d39c8eceb46fd30fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5cc503714cf321d17d604a45b46c2285a955b9ef4770f9605e74e79c67c19c4f702cf1e07fe382a67fab99d7d469996597c9734b87fed73504edbbe23f3fb603b7866cf6c63563ccb755c5813906e3909a3687bdcf2a4dbb1e5c1b9534dedd83ee071d1ce3b2a67ba1ddb6f9469b9c57749837575bf8372daf61d99df0fdbc1337b661bb3e259a1e3c29a80742b481845dbeb9627dd8ead08ce9d6a6ac7f6038f8b76de5139d3edd801a34c2b2cbe4b1aacab071c94d3b6efc8fc01d80e9ed933db9815cf4a1d17d604a45b49c228da3eb73ce9766c6570ee54533b7600785cb4f38eca996ec70e1a655a69f15dd2605d3de8a09cb67d47e60fc276f0cc9ed9c6ac78faebb8b026205d7f1246d1f0fce750fc3ca50983474d35b563871cfbe3a89ce976ec7060f7fd10f82e69b0ae1e7650ce3cc857d62df387613b64c3bc330799bdcf7563563c03755c5813906e2009a3680781e748fc3ca50983474d35b563471cfbe3a89ce976ec6860f7fd08f82e6970ff3aeaa09c7990afac5be68fc276c88679670e327b9febc6ac7806e9b8b02620dd201246d10e03cfb1d87932df37461e35d5d48e1d73ec8f9b7266dab1e381ddf763e0bba4c1fdebb88372e641beb26e993f0edbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a2e3c29a8074434818453b0a3c2762e7c9f43b208f9a6aea7738e1d81f37e5ccf43b9c0cecbe9f00df250dd6d5930eca9907f9caba65fe246c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a67a88e0b6b02d20d256114ed38f09c8a9fa73461f0a8a9a67e87538efd7154ce74bfc3e9c0eefb29f05dd2605d3deda09c7990afac5be64fc376f0cc9ed9c6ac7886ebb8b02620dd701246d14e02cf6bb1f364fa4f91474d35b563af39f6c74d3933edd899c0eefb6be0bba4c1ba7ac64139f3205f59b7cc9f81ed900df3ce1c64f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf178ecf8a67848e0b6b02d28d206114ed34f09c8d9da7633261f0a8a9a67e87b38efd7153ce4cbfc3eb81ddf7b3e0bba4c1fdeb7507e5cc837c65dd32ff3a6c87af3af3ce1c64f675a37e987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e6266a81b8aa75cc7853501e9ca4918453b033c6fc4cf539a3078d454d3733b6f38f6c75139d3cfedbc19d87d7f037c9734b87fbde9a09c7990afac5be6df84ede0993db38d59f154e8b8b026205d0509a368afbbe549250c1e35d5d48ebd093c5f8b9f27ddaebe9905cfd780e7adf8794a1c9533a9d6fb75608f6bbdcaabb70dafde34bc2a8234c8f0b603fff2205f59b7cc4b7e9ed9334731635b28ac0948f70609a3686f018f8b764395bdb55e97acbf61180637adcef76cfcf996e2354b43bd5ee190fc0a20cdfdcdaad30ed36c85f07fd96eaa3c670ccdd1b76f4a6cef4bc8bce45718d4db35448dd734e8858be7fcb33deea31712ff2c88af5ee37e8e79b9f8b652b6ef5c9cb6f0c458f692a8f74d5c7cc74e95bd8d5e97ac5feda3539b3af5bc14f73d693fda18652e80342da0fda884f6c3d656b8de37f302fbbe991f54b767c255ac75f3dec4675a977467213db639fdf52fee9ffda1acaedac5a86b126c17cdb6dba5f7e6fd3133ef22f0e52ca967b6eb38f471a0857b200137d6c7fadccf64ddb67b08030d1fd93cc36d7dd6e2e3200bf720026ec6fd7a90e1239b679fb75f0fb1700f21e066dcaf87183eb279f679fbf5500bf750026ec6fd7aa8e1239b679fb75f0fb7700f27e066dcaf871b3eb279f679fbf5080bf708026ec6fd7a84e1239b679fb75f975bb8cb09b819f7eb72c34736cf3e6fbfaeb07057107033eed7b5ed2765daaf1dddff4ef793a2676aaae99ee159a7fe64be579fcdf327af018f8b3ae5a81e241ddd734df7939ae30f9c35bcc2f1071cdf97adf1bb44929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e667cbf17fb5724ddeb248ca2397e363fdd9fd156af4bd6af9efd9d7d99cb7c5349ecf794e7924d8e0248f3efd756a79dafd9b07f11fb454f1b9acb6d698e3f2df3925f219407ebbfab77b5a3ead6eb96bc8b63cb3b55e1c6e354f2d2701d1705d5dbf994511ef4f464ecf99feb699ee1e949c77967fbbe04f238e88b2d7154ce745b70c22893e97111a46901e53ce1a09c7990afac5be64f008f4cf9c0e3aa0e06064f60f147a6d1643c83c9781e22e3b9998ca73719cf55643c73c87852643c6dc8782e22e39948c633828ca73f194f5f329eebc978ba93f13425e39941c6d3858ca7808ce719329ea7c8781e21e3b9958ca70f19cf1d643cd790f1cc23e34992f124c8782693f19493f10c24e3b99f8ce746329e9e643c9793f1cc24e3e944c6d3888c673c19cf30329edbc9781e23e3b98d8ce76e329eebc8781690f1b427e32924e3994ac65341c633888ce741329e62329e5e643c5792f1cc26e3e948c6d3848ce759329ea7c9781e27e3b9978ca739194f37329e96643c9792f14c27e36940c633868ca72d19cf10329e87c9785a91f1dc42c65346c6733519cf5c329e12329efa7827201b9e8bc9782691f18c24e31940c6731f19cf0d643c3dc8782e23e3a924e3e94cc6d3908c671c19cf50329e47c9785a90f1dc45c6732d19cf7c329e0e643c9790f14c21e31945c673868ce749329e07c8786e22e3b9938ce70a329e59643ca5643c8dc9782690f1b423e3194ec6d38f8ce71e329e66643c5dc9788ac878a691f1b426e3c923e04904e77f4b2701ff7f0d34f9e60b7e2f2cdfb23ee9a796f4eab838a7f9f9ebceb7acfba485017d3a0e6529d3f1e4179bcef9ce4d9e5eafcc4b7e85c0719284a73519cf34329e22329eae643ccdc878ee21e3e947c6339c8ca71d19cf04329ec6643ca5643cb3c878ae20e3b9938ce726329e07c8789e24e33943c6338a8c670a19cf25643c1dc878e693f15c4bc67317194f0b329e47c9788692f18c23e36948c6d3998ca7928ce732329e1e643c3790f1dc47c633808c672419cf24329e8bc9784e93f19490f1cc25e3b99a8ca78c8ce716329e56643c0f93f10c21e3694bc633868ca70119cf74329e4bc9785a92f17423e3694ec6732f19cfe3643c4f93f13c4bc6d3848ca72319cf6c329e2bc9787a91f11493f13c48c633888ca7828c672a194f21194f7b329e05643cd791f1dc4dc6731b19cf63643cb793f10c23e3194fc6d3888ca71319cf4c329ecbc9787a92f1dc48c6733f19cf40329e72329ec9643c09329e2419cf3c329e6bc878ee20e3e943c6732b19cf23643c4f91f13c43c65340c6d3858c6706194f53329eee643cd793f1f425e3e94fc633828c672219cf45643c6dc87852643c73c878ae22e3e94dc6733319cf43643c83c9784693f1e41b3cf87ff56e8f3caf7d42ff16c0ff97e987099aea75491a3946ab7b27c70c4d95f7a8a3f21e0baaa732983f0ae515f663c073cc11cf7183c7ccbb10e203c1b32386a6180f3b623c6230cafc616014ff8e00cf11473c470d1e33ef42880f02cf0e199a623ce888f190c128f3078151fc3b043c871cf11c3678ccbc0b213e043c3b60688a71bf23c60306a3ccef0746f1ef00f01c70c473d0e031f32e84f850f06c9fa129c6bd8e18f7198c32bf1718c5bf7dc0b3cf11cf7e83c7ccbb10e2c3c1b33d86a618ab1c31ee311865be0a18c5bf3dc0b3c711cf5e83c7ccbb10e223c0b3dd86a618773962dc6d30cafc2e60acd2f1ddc0b3db114f95c163e65d08f172f06ca7a129c61d8e18771a8c32bf0318c5bf9dc0b3d311cf2e83c7ccbb10e215e0d97643538cdb1c316e3718657e1b308a7fdb8167bb239e1d068f997721c4fb8126bc5d40dbaae39d41dba2e39d40dbace3a5a0bdaae31d41dba4e329d036ea7809681bc40fd0d6eb7807d05ed1f1f6a0add3f1aea0add5f16ea0bdace3dd415ba3e33d407b49c77b82f6a28edf09da6a1def05da0b3ade1bb4553a5e06da4a1def03da0a1dbf0bb4e53a7e3768cb74fc1ed096eaf8bda02dd1f1bea02dd6f1fb405ba4e3f783f6bc8e3f00da733afe20680b75fc21d0c6eaf8c3a03da1e38f80f6868e3f0ada9b3afe18686fe9f8e3a07d4dc70780f6751d7f12b4b7757c3068dfd0f1a740fba68e0f03ed5b3afe3468dfd6f191a07d47c74781f65d1d1f0ddaf7747c0c68efe8f833a07d5fc7c781f6031d1f0fda0f757c0268efeaf8b3a0fd48c72782f6631d9f04da4f747c32683fd5f129a0fd4cc7a782f69e8e4f03ed7d1d9f0eda073a3e03b49feb7825681feaf84cd07ea1e3b340fba58ecf06ed573a3e07b45febf85cd03ed2f179a07dace3f341fb44c71780f61b1dc7ef68ff56c78b8378dbf74f83eaa918f296fc549adfe97823238d2c5b00690af5cd4875bfa328a86effe578a03469ffb78226edff16d0a4fddf0c9ab4ffaf8226edff26d0a4fddf089ab4ff1b4093f67f3d68d2febf029ab4ffeb4093f67f2d68d2febf0c9ab4ff6b4093f6ff25d0a4fd7f113469ff578326edff0ba095e9f82ad0a4fd5f099ab4ff2b4093f67f3968d2fe2f034ddaffa5a049fbbf043469ff178326edff22d0a4fd7f1e3469ff9f034ddaff85a049fb3f163469ff9f004ddaff374093f6ff4dd0645ffb14343926bc059a1c13be069a1c13be0e9a1c13de064d8e09df004d8e09df044d8e09df026da48e7f1b3439267c073439267c173439267c0f343926bc039a1c13be0f9a1c137e009a1c137e089a1c13de054d8e093f024d8e093f066db28eff04343926fc14343926fc0c343926bc079a1c13de074d8e091f8026c7849f8326c7840f419363c22f409363c22f419363c2af409363c2af419363c247a0c931e163d0e49820c78826a0c9fd6a3525bfe05414544ff99097309505f11e73702a83f87c28bb4c8bc978d690f16c25e3b9998ce72a329e36643c1791f18c20e35941c6d39f8c673d19cf6e329e5d643cd793f11c23e3394ac6d3948ca7808ce745329ecd643cb792f1dc41c6730d194f828ca79c8c671919cf40329e75643c3bc9787690f1dc48c673848ce73019cfe5643c8dc8785e20e3b99d8c671319cf6d643cd791f11492f15490f12c21e31944c6f33219cf27643cdbc8788ac9780e91f11c24e3b9928ca70919cf4a329e0d643ccdc9785a92f15c4ac6d3808ca72d19cf22329e21643c2f91f17c4ac6d38a8ce716329e2d643c07c878f693f15c4dc6739a8ce762329eed643c6f92f12c27e379858ce706329ecbc8781a92f10c25e3594dc6f32a19cf3e329ebd643cd792f15c42c6f31619cf52329e33643c6bc9786e22e3b9828ca731194f3b329ee1643cabc8783692f1ec21e3a922e36946c673828ce738194f11194f6b329e3c029e047004a0c9ff1b8026efeb9e014ddeef3d0d9abcebbb1d347937780168bfb668f9163e61f818347937631e6872bdff1168f2cce05cd0e4bc41f257f38b9a9fcf9f6f2967030bff479672ceb32c8bdb5b96290be2ddde98575970fefbd785c0318f84a735194f1119cf71329e13643ccdc878aac878f690f16c24e35945c6339c8ca71d194f63329e2bc8786e22e3594bc673868c672919cf5b643c9790f15c4bc6b3978c671f19cfab643cabc9788692f13424e3b98c8ce706329e57c8789693f1bc49c6b39d8ce762329ed3643c5793f1ec27e33940c6b3858ce716329e56643c9f92f1bc44c633848c6711194f5b329e06643c9792f1b424e3694ec6b3818c6725194f13329e2bc9780e92f11c22e32926e3d946c6f30919cfcb643c83c8789690f15490f11492f15c47c6731b19cf26329edbc9785e20e36944c6733919cf61329e23643c3792f1ec20e3d949c6b38e8c672019cf32329e72329e0419cf35643c7790f1dc4ac6b3998ce745329e02329ea6643c47c9788e91f15c4fc6b38b8c673719cf7a329efe643c2bc8784690f15c44c6d3868ce72a329e9bc978b692f1ac21e3594cc6936fe139ed8847de9d9475cbfce9af78de478dbc8f5e20791f36f23e7c81e47dd0c8fbe00592f77e23effd1748de7b8dbcf75e2079571979575d2079ef32f2de7581e4bdc3c87bc7059237f3798bfa3e865c639fd0bf09f83f8edbbddd11e3698351e6b703a368f85da4fe8e78a2ce79fa13e4adbc18a8e372af2f01ff1f088caeea547f8351e66d750ac7a51ee88827ea5c6d2041deca0b79c64bfaca13f07f1cf7cb559d1a6830cabcad4e1d069e418e78a2ce310711e4adbc907724e459d304fc1fc7057155a706198c326fab5338aed510473c51e7c64308f2565ec83bcff2ee5802fe8fdfe97655a786188c326fab5338cec450473c51e7f44309f2565ec83771e4db0209f83f7ee7d4559d1a6a30cabcad4eed059ee18e78aa0c9e2a8b175f56deca0be963d8a37f13f0ff11c0e8aa4e0d371865de56a7aa806784239ea86ba81104792b2fca755cfa1613f0ff72607455a746188c326fab53bb80a7dc114fd4b55f3941deca0b79c65d9ecd4bc0ff71dc5c5775aadc6094795b9dc271e82b1cf1445db356d443de51d75ff59177d4b5447de41d755e5c1f79479de3d547de51e72bf59177959177553de61d751ca98fbca3da44bf7ffbfd3beebcbfcc6349959177553de6fd65eedf5f669bfa65b62dfebcc5b76bf595b73f6fe13e6ff92cbebc93787dda24c6f5e27d816dfa17efed6c054deeb56c014dee976d064dee79be0a9adcb7de049af43d6c044dfa8fde024dfa00b16f52bef97b1c3479260dfbc4648c89a3a0c95814d817f32b1d3f0cda1c1dc73e80d93a7e10b45fea38de7b9ea5e3fb41fb858eef036da68eef05ed431ddf03dacf75bc0ab44a1dc77b3c33747c17681fe838de5b98aee33b407b5fc7df046d9a8e7f0ada7b3a5e01dacf2cda541ddf00da141d5f0fda4f75fc15d026ebf83ad07ea2e36b419ba4e32f83f6631d5f03da8f74fc25d026eaf88ba03dabe3ab417b57c75f006d828eaf02ed873abe12b4f13abe02b41fe8f872d0beafe3cb401ba7e34b417b46c79780f68e8e2f066d8c8e2f02ed7b3afe0968a375bc1cb47c1d1f015a031d1f0e9abc17341434f9d6eb10d0e47dee41a0c937df0782d644c7fb8326cf92e37834f27d491c8f46de01c4b16ce43bd31f8126df6ec0b167647c101ca346be71f52bd09aeaf81cd0e45bb2b34193f7c57f099a7c537e1668f29d9f5f8026cf86cf044dbe17f92168f28ee1cf4193ef58578226df8698015a331dff0034f966d574d0e4bd9df741936fd54e034ddeb77e0f34f966fdcf402bd6f1a9a0ddace35340bb45c77f0adaad3a3e19b4163afe13d0e4db13934093ef2dfc1834f966d88f406ba5e313419377279f054dc6b77917b4363a3e0134f98edc0f416ba7e3e3416bafe33f00ad838e7f1fb4a48e8f03ad44c79f012da5e3ef80d651c7c78056aae3df03ad938e4bbba0f63fb55fbea6e7cb82f8cea7547e678373a73c63be0ce2c2803c719e6315010fe6752af6b2a792f8cc53be5eafd4975390f789d8f34ea6f33ea9d755a0d77bc2c8bb00d2fceddaea6d734c6b0df472a78de5f01a58d62dcbb405fdb8b1eea6babc271d95f784c124dce883a469a01b4d752c3ba8e38e9ea54aa97d40ea5a001ee25406717c5e307eaf52493c07af0dcf49e0897f3f4996b8aa13b86fc5d986d8ee019975ad08d2e09893c71df887fbbaac5be6253fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a47fa13b0cf5cd2bd46c2281af6759d8c9f27897daeb27ed5afb311fa755cf7ef35d4eb6d6794b900d27c047d4e5b74bc10fe2fdb2d6a5b3ae827ac715b4a7e85509e93c0e3a2bf380ff292759fb27821f1e2d8f24e55b8f1389554cf99a83ef6d386afaf593c75b5bf62df2d7a8afbeb598307fb460b81f775fd9b80f5bc0e6570b08fd7582f243fdc974e8126f1b3c0e8623be3b144da83b67a1efba625cd69edadf48bc7bfed534997edc631285359707efd2e80346f40dbf7968ee3b321af816fef5afe2f534dfdd4e29f2af391f8cb9cc467e065fb1eb1e47d085863cafb9ce7eff374907c442f80f80fafab4e2be9c40ff15ad8f1fbd6c86e2e77d658ae08d21cb594bf2c88b7fc470c9e2306b3da266f433d7b178effaedaa4a3111eb5058f240d9e07b9fa668fd9460a87e4a7d2c8f66f64a4c1731649f301b451aa2cd2ce4b39f1d9163c06b83a8ebd66944fe66de7c62781d12ca3aa1fb32fabe6bdd09ffffa03b417713ffff507a843f89c5660acbf1dac5fb81a05d1c71649f367e338eae21a03b7a5e927fa2c69fe02edd00dfa61dc6ccef5bfacebb6a873fda30e7812c1b9d7de6aaae9f88ec798630e781c9533693b761d37ca5404695a40391d9cc7d4f81ee111c8dbc536472fe41cea84e14501a4f99f46db11e5235eab9eac97b2a4ace783ed2c6591349f19edd461074c2eb7db2128935aef294b59254d8366d5be34d4f1046c27bc6f72a5e5ff32d5d41e887faacc07e22f7312dffd94ed7bc092f73e608d29ef73de3b95f37dc947f402885fd1ac3aada4133fc46b6157fb88bcdb86ece672278ce58a20cd414bf9cb8278cb7fc0e0396030ab6dd204ea99d42397ede6c1088fda81479206ef1fcbb11ddf6fb41df75d3c5f5dd371ff14309aed269ebbb86433bf0b6bde43b59d0f4a1a3c279334b768e6a6c1b9efe3609bb3d1ed33ff25f8fe6a00e5088cb206069b239f4bd167f31e601bd04d9fe57fb66b86b6e0737ddc9f166ef35a00af4784db3ccee0f5480970ab7a2fdb09ef238af686fe75744e5e8ad75b728c31cfc9f13e5a1760c76585eb754b59c403499b0fff97ff7d16d8af4f3e6f39337ec65846f9fb8691ce964f135836b677354a924993ffb4c1896db3a4b3f92afb01d6395997b9afe07d5149d3d76893ccb46adb4f6d5aed8f6c47f10edb13ac93aefa60ce18e59779c94f31ca3da033c0e3e23e4ab6ef4fb9becfe6a88d4ee2bd8bf8beffd06d94ed9ecb6b865745c1f9f7335cb6e9517d39272c79c7e7456ab4adbfdfe6457df6f7477971dc92777c5e74aeb0b573362f8e59785cdc7fa9c98b6396bc63f462aced9e88cd8ba3161e57d7db515e1cb5e41d9f175dacf7ab6c5e1cb1f0b8baee8af242f2cb96f918017313231e4fdea5a3f0be544d5e1cb6f0c47f4faa662f0e5bf28ecf8b92ce35f57fa217872c3caefa31a3bc3864c93b3e2fba76b3ddbfb07971d0c273b09ebd3868c93bc67a31c6767fc9e6c5010b8f837b8d357a71c092778ce7879df15e634d5eecb7f0ecaf672ff65bf28ed18b72db7d509b17fb2c3caeee834679b1cf92777c5e8ceaa4f2de5b0b2ff65a78f6d6b3177b2d79c7e745795795f79e5a78b1c7c2b3a79ebdd863c93bc66ba874bda8aa851755169eaa7af6a2ca92777c5e8c4e9f6bedae8517bb2d3cbbebd98bdd96bce3f322993ea6eeaa8517bb2c3cbbead98b5d96bc63ac17e9ebc99db5f062a78567673d7bb1d392778cc79174bdd8510b2f76587876d4b3173b2c79c7e7c5d8f4fda7edb5f062bb85c7d5b88c515e6cb7e41de33d9774bdd8560b2fb65978b6d5b317db2c79c7e745c7f431756b2dbcd86ae1d95acf5e6cb5e41d9f1763d27d625b6ae1c5160bcf967af6628b25ef18cf3bd3edc5e65a78b1d9c2b3b99ebdd86cc93bc6f3cef4fd8b576be1c5ab169e57ebd98b572d79c7d876a6cf3b37d5c28b4d169e4df5ecc5264bde319e77a6bdd8580b2f365a7836d6b3171b2d79c778de993e8e6ca885171b2c3c1bead98b0d96bc63ac17e9b6737d2dbc586fe1595fcf5eacb7e41de37dad74dbf94a2dbc78c5c2f34a3d7bf18a25ef18af47d2f7f8d6d5c28b75169e75f5ecc53a4bde31f615a5cfc1d7d6c28bb5169eb5f5ecc55ac8dbd5fb3a92873c8bd5daf0a200d2fc87f12c56948fb20e7cae0ccbf272ec65c93c57b626a22c2f435924cdff369ee55be380c95159d375e62528935aef594b59258d7c085ff992afe309d826af836f9759fe2f534dcf20897faaccabe32f73baaebe009c65900fe6bd0a5863cabb04f39667d3251fd10b20deb479755a49277e88d7c2aef69117751cd9cde5d61acb15419a172de52f0be22dff6a8367b5c19c7eef01ea99d423376d5786e9c5088f5a834792069fd93beb88c77c865038243f9546b67f23238d2c5b0069aed31eca73bbf21ca49433119cffdca4a3b6ac04d965dd322ff9e1fbb2a780d12ca3aa1f83e1d9cf0e5a6f1f546b25c20deb29353455d64e8eca2a79c9ba65be1330ca9814a5f5cf98aa2d63478351f17471e0198eb321534dc78b2ec0d3d9018fa372a68f435d8d327532ca540469f0ddc6ae0eca9907f9caba65be2be4ed629ba317724cbeddf0a200d27481f6ac261f651daafe965acad2c3715964ddd22ef5a887bcbb1979a78cbc13c1b9db39086adebfba01737707cc6abd3de35f6f7affba53af4bea94e4938232f5020fe22a13e62de779928fe805107f18cef3249df821c72f61577559b625b29bcb7531962b82343d2ce52f0be22d7f4f83a7a7c1acb6491f38b773b03fa4eb400f8343e653e05dcf08ef7a807792068f7f1d1c79d7dde091f90ec023e7385d41937305e14fc0ff93f5c06db67b5d2ddca27503c60e16c6d2f819d3e73a1d0c46992f0546d1ba034f37479e99dbfa76c31f3c2e3732d2c8b20590a61c8e8d094b5ab5dffd2b944bc62e8c719c9f749bdec8815f38ae6200fe04868701f825e56ce880e7e2a07a6cc5199553a6973f33a6ff984cd7a3a0151898f89b6729463e68186f60d182e0dc21240b409321241b82966fd88243574a7a19d2ce855de887acbbc0e06c022c71e68dc36fca5453d5690c3c2eaab2aa3a97e875e9aa3368faf8ca31583f1a1a9c75a93bea7f0d6a4817b52e57dbc1dc27ca60deac83058ef26f00e52d8379c94f6d9b421d9f5a5ef16c9fe9cfcc9c346672e50c34cadcb1319e179cbb01ccdf28c35ded745801b0c0d8383434ca850d86fc4f36ccc5f17396e218b7a63701e427d3c5e0db450e7c53eb97b16a2bca274eec3773d4c4f1157d674eaea81c3f65326ecd268673515b5afedf08345b138f69d584cd162edbd8a2d9261c15b8096872e4ba0834e1b918b4061097f4e69671525d5bc0fa659752ff53e634d4056f1c545701391cab7655edbfea54eed220732a745990d99c6aa86135b4b01a4a580d1dac860a56a36caaaf5aa89e1c75f6a486f65543f9aaa17bd550bdc5416628de5b82eaa176d5f42e70de16644eb5d4d0b9ad82ccd0b8ea76a57a5d5d7dda4d7d4a439db2ab534b759aab2eebd42588baada64e3dd52d0b75fb4a9dc6a9536475faa74ed9d42588baf450978aead2a9b7f6ba4f18ee0ac3dd61b8270cf786a16f18ee0bc3fd6178200c0f86e1a1303c1c8647c2f068181e0b43bf303c1e6486921e10862782cc50d34f069961a807079921aa9f0a32c3570f0b32435b3f1d6486bd1e196486c41e156486341f1d6486ce1d1b6486da1d176486f09d106486069e1864861c9e1c6486329e1a64864856c329aba197d590cc6a486735fcb31a2a5a0d213d370cf382ccb0d30bc2b0300ccf85e1f920336cf7e22033ccb71afe7b5990192e5c0d23ae8617575d09aa0b45752da8dbf6aafb4add5a565d5aea96b7ea8a555dd3aaab5e3dbaa01ee5508fb6a8477dd4a34fea5130f5689c7a54503d3aa91e25558fd6aa478dd5a3d75541e6d1fcbd41e6d50df52a8b7ab547bdeaa45efd3a1c645e0d54af77aad725d5ebbfea75e89341e676b67ab55e7571aadbd8ea96bebad5ad6ebbaba1e5df0ac3d7c2f0f530bc1d866f84e19b61f85618be1d86ef84e1bb416658e27782cc10c83f0832c328abfaa8866cfe719019f6f9a7416688e9f782cc30d51f049921b13f0c32c36aab21b8d510debf0e32c380ab61bfd5f0e7bf093243daff360cbf0bc3df85e1f761f84318fe3e0c7f0cc39fc2f0e730fc4318fe310cff1486bf84e19fc3f02f61f86b503df4353616bfd73337ebf9f2caca3193a65616574e299e347362e5f8a913e716cf1e5f39ae78caac31d3c74e9c321b175ea39b2719b7bbcff4e9e5738bc74f1e3d664ef1949995c553c6168f9a3273f2e8730ed4c7f442d79f9f63f9e8d1d1997d23ff0b907ea78e99bea7979311d11fa8b96c3faf8b211fd565a1ff55c702cdd1472fb97d322073ae5b3c63e294cae264f1e4f06f78709d327bcce8f6c5f8bf19a1c9332a8b6754964faf2c1e3b7dcaa4e292f6b8de8f1bd7a110ffded80dcc2557d5cd9ccff4f8ce75aa62a7aeab8303ef5f5737d2df5ff70548ff54c74cff475d4af87febb2d0cdcdea46d8a659a42d33668eaa9c5e5e5119bd70f28b2cdcb9591d8a796f1d8bf9dfeb92d97fd665a16b9bd78db073f33a6436328bcc82ff07d6af973f08fc04009b2d6c6f000000212f1f8b08000000000000ffed9df77f1cd5d5c667d55cd65acbbd0202e322abad569265b9ca40006363834d31cdb8c960b02d638b964220150209bca9d4407a25bd92de437a4842494823fd87fc0bf9bce7cedef3ead1f51dbd5a31573963ce7c3ec773e7f1ddb9dffbcc99bbab3bb3b3b9a8bcfc932267cbd5148ba2e317feff3ebb2ebeb8a523c57d154372e632c2599511ceea8c70d66484b336239c7519e19c9011ce8919e19c9411cec919e1cc6784734a4638eb33c259c808e7d48c70366484735a4638a767847346463867668473564638676784734e4638e76684735e4638e7678473414638176684f3a48c709e9c11ce5332c2d99811ce5333c2795a8a9ccdc0c973e1a7dbf562bb5e62d74bed7a995d37d9f572dbc71abb6df6d942d14ad1e6fc5fbb61a63093e225e7ff3a29ba28ba2956d8ff6bb4ffd743b192a2976215c56a8a35146b29d651acb79e6ca03883e24c8ab3285e467136c53914e7526ca4388f6213c5668af329b6506ca5b880e2428a6d14db292ea2b898e21287e5528a1d1497515c4e7105c595145751eca4b89a6217c56e8a3d147b29f651f453eca7b886e25a8a0314d7515c4f7190e210c5618a018a231437501ca5384631487123c54d8e673753dc42712bc5cb1dce5750bc92e25514b751bc9ae2768a3b285e43f15a8ad751bc9ee20d146fa4b893e22e8a3751dc4d710fc59b29de42712fc57d14ff43f1568ab751bc9de21d14efa47817c5fd140f503c6859f8447888e2618a4728de4df128c56314efa1782fc5fb28de4ff1018a0f527c88e2c3141fa1f828c5c7283e4ef138c527283e49f1298a4f537c86e2b3149fa3f83cc51728be48f1258a2f533c41f1158aaf527c8de2eb14dfa0f826c5b728be4df11d8aef527c8fe2fb143fa0f821c593143f723cff31c54f287e4af133abfddcae7f61d7bfb4eba7ecfa5776fd6bbbfe8d5d3f6dd7cfd8f5b376fd9c5dffd6ae7f67d7cfdbf5efedfa0f76fd47bbfe935dffd9ae5fb0ebbfd8f55fedfa6f76fd77bbfe875d9beb6333a695cb13a3a1a52f4a69cce9eaef35f3e36ca67bfdcd5cdba9b6ffc7eb46abd7d86d5ee7ac5e6bb76b1dbdce6ed739fb9968b7273a7ac16e171cbdc16e3738fa74bb3dddd167daed998e7eaadd3e15f4bcfdbf72c7ca2ba3555b29071ae75f1568b556ab06ad8e7707da04abd582c6c7b70eb449569b00da64ab4d042d6fb549a04db1da64d0eaad9607ad60b529a04db55a3d680d562b806653339a0ada74ab358036c36ad3409b69b5e9a0cdb2da0cd0665b6d266873ac360bb4b9569b0dda3cabcd016dbed5e682b6c06af3405b68b5f9a09d64b505a09d6cb585a09d62b593406bb4dac9a09d6ab553403bcd6a8da0f179792a68a75bed34ab999ce2712e7e8dd5ab403b9dcf65d016f3790cda123e87415bcae72f68cba06dd69af87c066db9d5389fcdffadb0e5be28adb1acb4c7ecb727edfdd29ecd7e7bd3df6fd18c8daba221affba09d1ef06ab52da7784f4007b69db3c1edb05e03e5b3a12ed7633f784c627633ceacb4e5d523bc6e85f3ba02d459e9e97f5f946eff7b1d9e5e87b916ca817276bfe6eca8978a73f622a8ebe61ebf3f9e8839bb1138d2cfd9ce4ecdd9512f15e7ec1ea8ebe61e7f563b1173f652e00890b33d6172b654d49c2dcf8f44913ff7f8ef86133167fb8123fd9cedd69c1dfd5271cede0675dddce3bf614fc49c3d061ce9e76c4f8f7e3618f55271cede0375dddce3f994133167ef008e0039bb47c7d9512f15e7ec8350d7cd3d9edb3b1173f65ee0483f677b03e56ca7e66c54bed61545fedce379e61331671f018ef47376afcecf8e7ea93867bf0075dddce36b1e2762ce7ecc96cd75869fdbeb0c0b41fb85d54e02ed97563b19b4a7ac760a68bf826b83acfd9aaf1b82f61bab9d06dad3ce3555a33d63b5d3417bd66a8b417bce6a4b40fbadd59682f63bab2d03ed79ab3581f67bab2d07ed0f566b06ed8f566b01ed4f566b05edcf566b03ed05abb583f617ab1541fbabd53a40fb9bd54aa0fddd6a9da0fdc36a5da0fdd36add5633d724f9dad7f7ad3611fade17a597a3f1f5ae68f89273b6fba0bc3c2c4fb1100dbf0f88db6a49bfad4ed3f7e668f47d6f019ed6007dcf431ba3e169059eb6f479e2efc9b5a7bfdff818373b9ee6a1ad66e8573140bf72d016ef9bb7b9bd0268386e143d8c1de93396f05e27de376f7700236b388ef138cce78f798ff917f0063897e2cf19dc1e7fff97395a40e73adf6a1862fbb7d5eae1ff714c6f73b4407919e705b7c5fbe6ed7660e4feb48d3f6369b48cad0e63a83122076df1beddb6f17c5f3efe9e8deab81640fb2f8c49a5b18e49f5c0d6048c4d817c4c3ad652da0ef17e958336786c63cfdb41e73acf5595d7666c9b9c1b620b70fe952afdfc86e341fa795c2ae2793d1a9e22f08438f7039daf457cdfff4f946eae951cafda1caf0a50a703fc2b05f06fa4cf21dc9e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6fb2ff0fa26d76b12c2c85a3bf08498e78fbf4bcefbb26b735de721b8ae93fe758b5211af59f27d7b4b9c3ed7409dc77343751fb565dfb541bca6d914d6bb51dd67511f1d7f2d36e435c4a4ebc0beeb978da9b55dda1bea7a9b79ce85792641b3e36b93c7d300f7a90cf334e7788af7c72d73784c9e3e5f35c416e2da5fa5d722d12b2ea7796d0fef31087b5ccae307e74255347cfcc0f799ced4db1e7e0d93af97773a6dd7409dafe4868e0ddf03c9bf75e0def364ea7439fbe6d72c01bdcbd977837d2d73d43afb6f86d7729dafc398ba1b7235c4fd1f382e47d0575cfaa08cd7cdd37f1f2e5fc72f56c053029e10e34ca0cf1b453c07d2be8edfe578e5fb1cc3753ac1bfae00fef93e8bf236b7a7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1bba2cc9a877aed4218c7e9de87f87a063f7784f76faeeb6cad1a6a37f47538bee6b4d4e9730dd4b9af6aa8ee765bae8f8ebfdf21e95806b89e37e2b1e4f6eaa13f782d28d4f7b93b1c9e0e8f175c6e4cadedf275fcf43d1eba8e5f747c6df7781aea7cc56bace8299eaf6d0e0f5e1bad8f8ebfb7240ffb198f7b8792f282dbc373a903342ee3f7a3431c677c2f71efebe1f6f0faf5f5d6db8628d4b12f15438e1bddd0a7bee8f8fcae813a4760ec3b6acb780f07de3b7287e7ff7919e93a35fb17e8396ef1f15d099c7dd00eb6dd0bac29b5dd816de76c703bacd740f9f6aaa1baee73cad86b6637e788fb2c35dfebda9cd715a0ce0a4ffffba274fbdfe3f0f438cce698dc08797607bcff871a93562478b4043ce23af83928d43d79ee18e9dedf88f7edd53975f0330bd7b90bc6a8a4fb477df71c867a1f4bbae7d0f7d9b8048c6e1fddfb3c5feaf7693d00e345daf7693d003984f76945cefe97c2fe99ab2e4a7e6fe13a8f38fb773f93f36bf03e30aef3188c174fc1671df7f337de33351e7f5f25dd27cdede1e71a3cb7ffbfbe1be66ea8df972233e604b2e0e704aef351e798752570b7785efb78c26bd92b7e0e15fefde2fa677c48fd19b2f69cef71fac279bd02fac2753eeb7c060cf59ceff4fb3afc33098f031d9ebe729d2fc1b9f6047cc6e3e3847f773ce9f97f5e46fa0c88cfbd5d957e9fe3e38bcf77ed8376b0ed35c09a52db1dd8367f06e47658af81f20f614ce77aec077bcdece61ce1cf51c8eebeaed3795d01eaf47afadf17a5dbff550ecf2a87d91c93af419e3d099f01438dd5bd091e2d058fb80e7e3788df47f019b2bef79850f7f627bdc7f89e4189e3f35341e7d5fc6ceebc9aef3302d7e1d7e2678467609ccd7beabaf385fc7e99e67dc3f85d896668f7794fbb7d29fbd90abef5c1367e2ef86fb61de0b9a5f17744f0b982cc804b1f9499a100afabca00637506186b32c0589b01c6ba0c304ec800e3c40c304eca00e3fffddeb760c67c0618a76480b13e038c850c304ecd0063430618a76580717a06186764807166061867658071760618e76480716e0618e76580717e0618176480716106184fca00e3c919603c25038c8d19603c35038ca76580719132a6c2b82c2c6369ac8c8627d4ef1356f29b78e3f1fb842d9eb6025c172955da77bc5612e2f96995fe5e223314a2e37fff2b106369ac8c86a72d7d9e8a7f5fb30d3cf3fd0e6600c617f51b52929edb86f7a72f0fcb587a31cf960b715fe7589f1f86f7182c0fcbf8a29e7116e21e824a9f71e6bbe7617958c6d2581943ddcf8cdfe7180d0f7e3faec3e35900c6d25819437d0f02bfab351a9e4ef0ace4f12c006369ac8ca1ee99aaf49e3ebcb7bbd3e3992446e449fbf9a29d9eb6ba05f49d19b2c63829038c9333c098cf00e3940c30d66780b19001c6a919606cc800e3b40c304ecf00e38c0c30cecc00e3ac0c30cece00e39c0c30cecd00e3bc0c30cecf00e3820c302ecc00a3fe5da88cff6d46e4694c8f67d8fc07b615e27bad95f67d858727c5ef7d0eeb3bb615e0192715f71d9f059225c6ee0c30067e9e8dfaa88ccaa88c7a5eab8fe219d547f5511995511995f1a5ce9885315c1933918fa5b1321a9e95813ceba980672578c6af5b9e01c6151960ec0ecb581a2ba3e109f18ce13cb4311a9e5ef08c5fb73c2c6369ac8c8627c0f31063cf7a2be0c1e706f67a3c0bc0581a2ba3e1591dc8b35515f0ac06cf56793c0bc0581a2ba3e109f1ecc73cb4311a9e35e0d96a8f6701184b6365343c6bd3e7893d5b5301cf5af06c8dc7b3008ca5b1321a9e75e9f3c49eadad80671d78b6d6e35900c6d258190dcffaf47962cfd655c0b31e3c5be7f12c006369ac8c13414f9127f66c7d053c7de0d97a8f675219bb32c0d89d01c62cf8a88cca288951cf6bf55112a3faa83e2aa3322a637619576480518fb5324a65dc903e63a952c60dc0d3973e4f47a07ec6bfe37586dd578acf962819afce74bc5aef7855803a67807f6706f02f07edf2be799bdbab94f97401cc81da2ef1ef4baf77daeb76fc30cb59765d0b7a1778fa325be6dff0e3faf87b6e5ce712fb8329fcdba0bc54417fcf4abfbf1d239ddbdc1ef2ac11c6b340184faf309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34118cf22613c6b85f1ac12c63347184f8f309e69c2789609e3c90be3a915c6b35818cf5c613cd385f11485f14c11c6d3248ca74e184fab309e75c278560be399278c67a5309e19c2783a85f1d40be399208c67be309e99c2783a84f11484f1b409e399288ca745184f4e004f3e3afe9e853cfcff06d0aa9cd79af1b366dad0ff9f6df52a78cd39b65cedd9f7d9a0f1b5dd733caf459fce86bef4d972f1c52db14fd8561f6c737bf5c0718e109e16613c1385f1b409e32908e3e910c6335318cf7c613c1384f1d40be3e914c6334318cf4a613cf384f1ac16c6b34e184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d184f8f309e39c2785609e3592b8c6791309e0dc2786a84f1340be3992c8ca75d184f83309e92309ed9c278960ae359288ca75a18cf12613c9384f14c15c6334b184faf309e05c278d608e3a9f2f06c08c4c3d76f79dfbcbd4148db018e43fcbdf87303f569a3dd57addd2ff3737b3550e7b1baf2da7c7ec2d732977bbd1dff76d8081e6d0cd4173e1e39e7f8046ebb0bef2b88802172fc893c3c21eec708d4cf617998e2f3198ac6abf31cafdc6357803ae7827fe705f0cf97dbbccded29b3322731e3ef5b306b1eea750a6164edaca03c5dc54a7f83e33ce009f15e11c8f7781cdbe4f4a9d3e33bd7c15cdd14a09fbe7387b73779da6e8cd2f562f328bcd8ece1d93cce5e707b95329f9b4166f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466093e1b1e7ea606b3e6a15e8f1046d63686e589bf6fd4130d5f72ce761f943703cf7901fc09d4cff81ef2f39d3ef5787ce73a787e9d1fa09fbe7387b7cf87e35009f3a60c32abcf6363363cfc6c4466cd43bd954218593b2f2c4f3c8ead8c862f238d63e7034f88713e503fe3716c8bd3a7951edfb90e9e5f5b02f4d377eef0f616380ecaaccc3e66c3c3cf6860d63cd4eb15c2c8dae6a03ca5f8fb8dbdd1f065a4716c0bf08418e703f91e8f635b9d3ef57a7ce73a98ab5b03f4d377eef0f656380e95306fca20b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcf2f1d9f0d0fff7608b3e6a1de2a218cac9d1f94a733beeeb02a1abe8c74dd612bf06c499da77cdd2180eff175870b9c3eadf2f8ce75f0fcba20403f7de70e6f5f00c7e14467de944166cd8df161d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e6296901b8667b52d336b1eeaad16c2c8da96b03cf1730f5647c39791eedbb90078b606f027503fe3fb762e74fab4dae33bd7c1f3ebc200fdf49d3bbc7d211c076556661fb3e15963cbcc9a877a6b8430b2b6352c4f3c8ead89862f238d6317024f88713e503fe3716c9bd3a7351edfb90ee6eab600fdf49d3bbcbd0d8e83322bb38fd9f0acb56566cd43bdb5421859bb202c4f3c8ead8d862f238d63db8027c4381fa89ff138b6dde9d35a8fef5c0773757b807eface1ddede0ec7419995d9c76c78d6d932b3e6a1de3a218cace1e71f66fb4f7a3cdd0560a982b6428de191d3775e305f78d9208c6781309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34818cf1c613cd384f12c13c69317c6532b8c67b1309eb9c278a60be3290ae399228ca749184f9d309e56613cf384f1cc10c6532f8c6782309ef9c278660ae3e910c65310c6d3268c67a2309e16613c39013cf9e8f8eb9c78fda41a34be9eb10eb48b6c790368559e36783fdb41e3bfcf791f663c9e3aedf8f6aa3ced6df7708d879fd8561f6c737bf5c0b15d084f8b309e89c278da84f11484f17408e399298c67be309e09c278ea85f1cc10c6334f184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d18cf1c613c8b84f1d408e36916c63359184fbb309e06613c25613cb385f12c15c6b350184fb5309e25c2782609e3992a8c6796309e05c2783608e3a9f2f05c9c3e4ffc9d32ee7b045cb8f441f9e2c0fe04ea67d1ecf712bbaf14bfcb127f57ed52c7ab0d8e5705a87309f8776900ff72d02eef9bb7b93d6556e62466c3c373ab78bd94ebb50a61646d5b589e787c6c8d862f238d8f97024f8071ac23503fe3716c87d3a7568fef5c07737547807eface1ddedee169bb314ad78bcb46e1c5651e9ecbc6d90b6eaf52e64b32c82cc167c3c3f72a306b1eeab5086164ede2b03cf1f8d8120d5f461a1f2f039e10ef1f81fa198f09973b7d6af1f8ce75f0fcba3c403f7de70e6f5f0ec7a112e61d1964569fc7c66c78784e9b59f350af5908236b9706e529c5bf51d91c0d5f461ac72e079e10e37c20dfe371ec0aa74fcd1edfb90e9e5f5704e8a7efdce1ed2be03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66c3c3df4d63d63cd46b12c2c8da654179cad71d9aa2e1cb48d71dae009e10d76502f91e5f77b8d2e95393c777ae83b97a65807eface1ddebe128e83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66363c6db6ccac79a8d7268491b5cbc3f2c4dfdb6a8b862f235d77b81278425c9709d4cff8bac3554e9fda3cbe731dccd5ab02f4d377eef0f655701c9459997dcc86879fb5c5ac79a8d72e8491b52b82f294af9fb647c39791c6b1ab8027c4381fc8f7781cdbe9f4a9dde33bd7c15cdd19a09fbe7387b777c271a88479470699d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d7ee9f86c78f837b398350ff58a421859bb32284f677cdda1180d5f46baeeb01378425c9709e47b7cdde16aa74f458fef5c07cfafab03f4d377eef0f6d5701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961783ab83dbbce43bd0e218cac5d1596277eee4147347c19e9be9dab816767007f02f533be6f6797d3a70e8fef5c07cfaf5d01fae93b77787b171c875dcaaccc1e66c353b26566cd43bd921046d67686e589c7b152347c19691cdb053c21c6f940fd8cc7b1dd4e9f4a1edfb90ee6eaee00fdf49d3bbccded29b33227319bb6f7a4df763c1e60dbec4fe4f0f0b227b01781fa198f077b23bfc7dc5e01eae031df1ba09f396897f7cddb7be13854c2bc2383cceaf3d8984ddbfbd26f3b1e0fb06df627727878d917d88b40fd8cc783fec8ef31b757803a98a7fd01fa99837679dfbcdd0fc7a112e61d1964569fc7c66cdade9f7adbe5e7a461dbec4fe4f0f0b23fb01761fa591e0fae89fc1e737b05a883797a4d807ee6a05dde376f5f03c7419995599995599995599995599995599995599995599995599995599995599965339bb6af4dbdedf2fc3db6cdfe440e0f2fd706f6224c3fcbf3f70722bfc7dc5e01eae0313f10a09f396897f7cddb07e03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66d3f675e9b71d7f1f07db667f22878797eb027b11a89ff1fcfdf591df636eaf0075f0985f1fa09f396897f7cddbd7c371506665f6319bb60fa6de76f97a1eb6cdfe440e0f2f07037b11a69fe5f1e050e4f798db2b401d3ce68702f43307edf2be79fb101c874a98776490597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d5e7978ecfa6edc3a9b7dd19cfdf63dbec4fe4f0f07238b01761fa599ebf1f88fc1e737b05a883793a10a09f396897f7cddb03701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961da3e927edbf1f7d9b16df6277278783912d88b40fd8cef7fb921f27bcced15a00ee6e90d01fa99837679dfbc7d031c076556661f339e2713d36b3bbe1f8edba8b26ba31db5e56ad08ed9720d6883b65c0bda8db65c07da4db63c01b49ba13facdd62cbcb40bbd5964ba0bddc96af06ed15b6bc0bb457daf26ed05e65cb7b40bbcd96f782f66a5bde07daedb6dc0fda1db6bc1fb4d7d8f235a0bdd696af05ed75b67c00b4d7dbf275a0bdc196af07ed8db67c10b43b6df9106877d9f261d0de64cb03a0dd6dcb8b40bbc7a3bdd9962f01ed2d1eed5e5b9e04da7db63c19b4ff8132afdf6acb53407b9b2dd783f6765b2e80f60e5b9e0ada3b6db901b477d9f234d0eeb7e5e9a03d60cb33407bd0966782f6902dcf02ed615b9e0dda23b63c07b477dbf25cd01eb5e579a03d66cbf3417b8f2d2f00edbdb6bc10b4f7d9321ea3f7dbf211d0781cb801341e078e82c6e3c031d0781c18048dc7811b41e371e026d0781cb81934ce9d5b40e3dcb91534ce9d9783c6b9f30ad038775e091ae7ceab40e3dcb90d34ce9d5783c6b9733b689c3b7780c6b9f31ad038775e0b1ae7ceeb40e3dc793d689c3b6f008d73e78da071eedc091ae7ce5da071eebc0934ce9dbb413bc996ef01ed645b7e3368a7d8f25b406bb4e57b413bd596ef03ed345bc67181c79fb78276ba2dbf0db4c5b6fc76d096d8f23b405b6acbef048ddf73de055a932ddf0fda725b7e00b4665b7e10b4165b7e08b4565b7e18b4365b7e04b4765b7e3768455b7e14b40e5b7e0c347e9f7c0f689db6fc5ed0ba6cf97da075db328f0be6fc33e70cf799fda887fe357bb85933e73473f745e97e66e2b678dfbccded1946f69bff6f1c194ba3656c73180d4f2980679843bc8cf4b75f09783a02f004ea67fcb75fa7d3a7a2d3a702d4391dfad919a09f396897f7cddb9dd07688638e5ed4dafd2e76bca8813acfda3739b31ac947de87c9df764f5f5604ee0bef9bc7a515e3d07697d376abd3368ebdbc8c747e750173770066b3df9ef4f71b9f5f2bedbe38a7b89d56e8532f7890569fb0ed9c0d6e87f51a28ffbb61a82ed7633ff8fd8bd94d2ef3b14476f77525e77505a8b3c2d3ffbe28ddfef7383c3d0eb339262f340c7104381fe21c58e170f0762b78d793e0dd0af08eebe0fb5f7b20efba1d9e6ea76dc3c39f713a41e3cf0a3807c1ffdf3c0edceeb8d7e9e166ad0b187d9f75dad2671cf1b34e1b30b2d60d3c5d813c738ff562c71f7c5fae73eaf06b6ba04e95fd63af211afeb706d735e7ddbfa05ffc37f37fa274c7f4ba007ee1dff311f813391e46e017f7b33600cfe468e86ffa63830347775fd3bfad7ff7be1ca0d53898b8ce79ba51051a96ab3d5a140d9fbac0294f9ebac029cf2ac7169c32e1fae64f29d32d9e1ee83f7460f0e2c3fd87f71ebdf5c860ffbecd03d72075ad438fa4493d4052d47c3d1a897e5274fcc14ff5cc64b845b0ff9c05a9b69da8b540c6be89d1907d3cb363deadcd8862666acc19694e4e63ad996931332b6626c5cc9c9899123333626642cccc8799e930331b6626c3cc5c98998ac6a83c13711af07c1f18cd5f08e66c37330966e6c0cc14987709f3e9d38cace6938479d733239d19e1cca764f317931939cca86c461c334a98773df36e673e9d9877eb5514ab29d650aca55847b1de7abd81e20c8a3329cea27819c5d914e7509c4bb191e23c8a4d149b29cea7d842b195e2028a0b29b6516ca7b888e2e2a83cf3776954bec27919c5e51457505c497115c5cea83ca3be2b2acf989b197233236e66c0cd8cb799e13633da6606dbcc589b19eaeba3f20cb499713633cc6646d9cc269ad943335b686607cd6ca099fd33b37d6676cfcce699d93b335b6766e7cc6c9c997d33b36d6676edf6a83c7b6666cbccec98990d33b35f66b6cbcc6e99d92c337b6566abee8ecab35166f6c9cc3699d925339b64668fcc6c91991d32b34166f6c7ccf698d91d339b63666fcc6c8d999d31b33166f6c5ccb698d995c7a2f2ec89992d31b3236636e403141fa4f810c587293e42f1518a8f517c9ce2718a4f507c92e253149fa6f80cc567293e47f1798a2f507c91e24b145fa67882e22b145fa5f81ac5d729be41f14d8a6f517c9be23b14dfa5f85e54cec91f50fc90e2498a1f51fc98e227143fa5f819c5cf297e41f14b8aa7287e45f16b8adf503c4df10cc5b314cf51fc96e27714cf53fc9ee20f147fa4f813c59f295ea0f80bc55f29fe46f1778a7f50fc331a9a49c581e209bbc1b37abb0707fb0f1d196c1c1c683c74e3c1c103470ededa78f381c16b1b076eea3fbaffe0c0cdf8e2ebec30c453961b8e1edd7d6be381c3fbfa6f691cb871b071607fe39e811b0fef3b862fbad3be68e1f12deedeb72fb9b1fbab5e04e9c3636cf423f6753c19bc71e4be7d7c2c867c662c2f7a7a8c1dbad8be8bacb1dbdbcbefd48dc70e0e0c36161b0fd3bfbb0fd26bfaf7b535e2ff1d23938f0d361e1bdc7d74b071ffd181438d1d6db8df47ebc6d089671ac6f0a2dcb4d1f73cfa5f16540aa2d9140300", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x0c57b7573675e1f7ee1d41a4e4ca808641ca7850826ca4966a4949230d821e85", + "id": "0x1310e0230fe8fa9a6c99193217d165b85d180bb916fc60afbedbe85721600ae5", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x15886fadf17a38ace1697ec5b797f23e63ca8e75bc337ed1201cf43f0b52b146" + "publicBytecodeCommitment": "0x2bbeaacc4ec3ee2fa51a3e2720a5772c6b079629e26e39c4a187fc6e4a56e46a" }" `; diff --git a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap index 233b49a285b4..192a72b643aa 100644 --- a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap +++ b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap @@ -1892,7 +1892,7 @@ PrivateKernelTailCircuitPublicInputs { }, "end": PrivateAccumulatedRevertibleData { "encryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000138>, - "encryptedLogsHash": Fr<0x000a6f11d0fee649628137ebedf70c9cf2e7b081a9e284c9608fc5741fa8fc7a>, + "encryptedLogsHash": Fr<0x0003100e66eb6812178264cd03595ddc65ec007a177d3b06abc1d8fc27357eca>, "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, Fr<0x0000000000000000000000000000000000000000000000000000000000000000>,